xref: /original-bsd/libexec/ftpd/ftpd.c (revision f3f8e977)
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.3 (Berkeley) 04/06/94";
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(p, 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(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
993 			printf("   File may not have transferred correctly.\r\n");
994 		}
995 		return (0);
996 	default:
997 		reply(550, "Unimplemented TYPE %d in receive_data", type);
998 		transflag = 0;
999 		return (-1);
1000 	}
1001 
1002 data_err:
1003 	transflag = 0;
1004 	perror_reply(426, "Data Connection");
1005 	return (-1);
1006 
1007 file_err:
1008 	transflag = 0;
1009 	perror_reply(452, "Error writing file");
1010 	return (-1);
1011 }
1012 
1013 void
1014 statfilecmd(filename)
1015 	char *filename;
1016 {
1017 	FILE *fin;
1018 	int c;
1019 	char line[LINE_MAX];
1020 
1021 	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1022 	fin = ftpd_popen(line, "r");
1023 	lreply(211, "status of %s:", filename);
1024 	while ((c = getc(fin)) != EOF) {
1025 		if (c == '\n') {
1026 			if (ferror(stdout)){
1027 				perror_reply(421, "control connection");
1028 				(void) ftpd_pclose(fin);
1029 				dologout(1);
1030 				/* NOTREACHED */
1031 			}
1032 			if (ferror(fin)) {
1033 				perror_reply(551, filename);
1034 				(void) ftpd_pclose(fin);
1035 				return;
1036 			}
1037 			(void) putc('\r', stdout);
1038 		}
1039 		(void) putc(c, stdout);
1040 	}
1041 	(void) ftpd_pclose(fin);
1042 	reply(211, "End of Status");
1043 }
1044 
1045 void
1046 statcmd()
1047 {
1048 	struct sockaddr_in *sin;
1049 	u_char *a, *p;
1050 
1051 	lreply(211, "%s FTP server status:", hostname, version);
1052 	printf("     %s\r\n", version);
1053 	printf("     Connected to %s", remotehost);
1054 	if (!isdigit(remotehost[0]))
1055 		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1056 	printf("\r\n");
1057 	if (logged_in) {
1058 		if (guest)
1059 			printf("     Logged in anonymously\r\n");
1060 		else
1061 			printf("     Logged in as %s\r\n", pw->pw_name);
1062 	} else if (askpasswd)
1063 		printf("     Waiting for password\r\n");
1064 	else
1065 		printf("     Waiting for user name\r\n");
1066 	printf("     TYPE: %s", typenames[type]);
1067 	if (type == TYPE_A || type == TYPE_E)
1068 		printf(", FORM: %s", formnames[form]);
1069 	if (type == TYPE_L)
1070 #if NBBY == 8
1071 		printf(" %d", NBBY);
1072 #else
1073 		printf(" %d", bytesize);	/* need definition! */
1074 #endif
1075 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1076 	    strunames[stru], modenames[mode]);
1077 	if (data != -1)
1078 		printf("     Data connection open\r\n");
1079 	else if (pdata != -1) {
1080 		printf("     in Passive mode");
1081 		sin = &pasv_addr;
1082 		goto printaddr;
1083 	} else if (usedefault == 0) {
1084 		printf("     PORT");
1085 		sin = &data_dest;
1086 printaddr:
1087 		a = (u_char *) &sin->sin_addr;
1088 		p = (u_char *) &sin->sin_port;
1089 #define UC(b) (((int) b) & 0xff)
1090 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1091 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1092 #undef UC
1093 	} else
1094 		printf("     No data connection\r\n");
1095 	reply(211, "End of status");
1096 }
1097 
1098 void
1099 fatal(s)
1100 	char *s;
1101 {
1102 
1103 	reply(451, "Error in server: %s\n", s);
1104 	reply(221, "Closing connection due to server error.");
1105 	dologout(0);
1106 	/* NOTREACHED */
1107 }
1108 
1109 void
1110 #if __STDC__
1111 reply(int n, const char *fmt, ...)
1112 #else
1113 reply(n, fmt, va_alist)
1114 	int n;
1115 	char *fmt;
1116         va_dcl
1117 #endif
1118 {
1119 	va_list ap;
1120 #if __STDC__
1121 	va_start(ap, fmt);
1122 #else
1123 	va_start(ap);
1124 #endif
1125 	(void)printf("%d ", n);
1126 	(void)vprintf(fmt, ap);
1127 	(void)printf("\r\n");
1128 	(void)fflush(stdout);
1129 	if (debug) {
1130 		syslog(LOG_DEBUG, "<--- %d ", n);
1131 		vsyslog(LOG_DEBUG, fmt, ap);
1132 	}
1133 }
1134 
1135 void
1136 #if __STDC__
1137 lreply(int n, const char *fmt, ...)
1138 #else
1139 lreply(n, fmt, va_alist)
1140 	int n;
1141 	char *fmt;
1142         va_dcl
1143 #endif
1144 {
1145 	va_list ap;
1146 #if __STDC__
1147 	va_start(ap, fmt);
1148 #else
1149 	va_start(ap);
1150 #endif
1151 	(void)printf("%d- ", n);
1152 	(void)vprintf(fmt, ap);
1153 	(void)printf("\r\n");
1154 	(void)fflush(stdout);
1155 	if (debug) {
1156 		syslog(LOG_DEBUG, "<--- %d- ", n);
1157 		vsyslog(LOG_DEBUG, fmt, ap);
1158 	}
1159 }
1160 
1161 static void
1162 ack(s)
1163 	char *s;
1164 {
1165 
1166 	reply(250, "%s command successful.", s);
1167 }
1168 
1169 void
1170 nack(s)
1171 	char *s;
1172 {
1173 
1174 	reply(502, "%s command not implemented.", s);
1175 }
1176 
1177 /* ARGSUSED */
1178 void
1179 yyerror(s)
1180 	char *s;
1181 {
1182 	char *cp;
1183 
1184 	if (cp = strchr(cbuf,'\n'))
1185 		*cp = '\0';
1186 	reply(500, "'%s': command not understood.", cbuf);
1187 }
1188 
1189 void
1190 delete(name)
1191 	char *name;
1192 {
1193 	struct stat st;
1194 
1195 	LOGCMD("delete", name);
1196 	if (stat(name, &st) < 0) {
1197 		perror_reply(550, name);
1198 		return;
1199 	}
1200 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1201 		if (rmdir(name) < 0) {
1202 			perror_reply(550, name);
1203 			return;
1204 		}
1205 		goto done;
1206 	}
1207 	if (unlink(name) < 0) {
1208 		perror_reply(550, name);
1209 		return;
1210 	}
1211 done:
1212 	ack("DELE");
1213 }
1214 
1215 void
1216 cwd(path)
1217 	char *path;
1218 {
1219 
1220 	if (chdir(path) < 0)
1221 		perror_reply(550, path);
1222 	else
1223 		ack("CWD");
1224 }
1225 
1226 void
1227 makedir(name)
1228 	char *name;
1229 {
1230 
1231 	LOGCMD("mkdir", name);
1232 	if (mkdir(name, 0777) < 0)
1233 		perror_reply(550, name);
1234 	else
1235 		reply(257, "MKD command successful.");
1236 }
1237 
1238 void
1239 removedir(name)
1240 	char *name;
1241 {
1242 
1243 	LOGCMD("rmdir", name);
1244 	if (rmdir(name) < 0)
1245 		perror_reply(550, name);
1246 	else
1247 		ack("RMD");
1248 }
1249 
1250 void
1251 pwd()
1252 {
1253 	char path[MAXPATHLEN + 1];
1254 
1255 	if (getwd(path) == (char *)NULL)
1256 		reply(550, "%s.", path);
1257 	else
1258 		reply(257, "\"%s\" is current directory.", path);
1259 }
1260 
1261 char *
1262 renamefrom(name)
1263 	char *name;
1264 {
1265 	struct stat st;
1266 
1267 	if (stat(name, &st) < 0) {
1268 		perror_reply(550, name);
1269 		return ((char *)0);
1270 	}
1271 	reply(350, "File exists, ready for destination name");
1272 	return (name);
1273 }
1274 
1275 void
1276 renamecmd(from, to)
1277 	char *from, *to;
1278 {
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 	snprintf(proctitle, sizeof(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 
1317 	if (logged_in) {
1318 		(void) seteuid((uid_t)0);
1319 		logwtmp(ttyline, "", "");
1320 	}
1321 	/* beware of flushing buffers after a SIGPIPE */
1322 	_exit(status);
1323 }
1324 
1325 static void
1326 myoob(signo)
1327 	int signo;
1328 {
1329 	char *cp;
1330 
1331 	/* only process if transfer occurring */
1332 	if (!transflag)
1333 		return;
1334 	cp = tmpline;
1335 	if (getline(cp, 7, stdin) == NULL) {
1336 		reply(221, "You could at least say goodbye.");
1337 		dologout(0);
1338 	}
1339 	upper(cp);
1340 	if (strcmp(cp, "ABOR\r\n") == 0) {
1341 		tmpline[0] = '\0';
1342 		reply(426, "Transfer aborted. Data connection closed.");
1343 		reply(226, "Abort successful");
1344 		longjmp(urgcatch, 1);
1345 	}
1346 	if (strcmp(cp, "STAT\r\n") == 0) {
1347 		if (file_size != (off_t) -1)
1348 			reply(213, "Status: %qd of %qd bytes transferred",
1349 			    byte_count, file_size);
1350 		else
1351 			reply(213, "Status: %qd bytes transferred", byte_count);
1352 	}
1353 }
1354 
1355 /*
1356  * Note: a response of 425 is not mentioned as a possible response to
1357  *	the PASV command in RFC959. However, it has been blessed as
1358  *	a legitimate response by Jon Postel in a telephone conversation
1359  *	with Rick Adams on 25 Jan 89.
1360  */
1361 void
1362 passive()
1363 {
1364 	int len;
1365 	char *p, *a;
1366 
1367 	pdata = socket(AF_INET, SOCK_STREAM, 0);
1368 	if (pdata < 0) {
1369 		perror_reply(425, "Can't open passive connection");
1370 		return;
1371 	}
1372 	pasv_addr = ctrl_addr;
1373 	pasv_addr.sin_port = 0;
1374 	(void) seteuid((uid_t)0);
1375 	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1376 		(void) seteuid((uid_t)pw->pw_uid);
1377 		goto pasv_error;
1378 	}
1379 	(void) seteuid((uid_t)pw->pw_uid);
1380 	len = sizeof(pasv_addr);
1381 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1382 		goto pasv_error;
1383 	if (listen(pdata, 1) < 0)
1384 		goto pasv_error;
1385 	a = (char *) &pasv_addr.sin_addr;
1386 	p = (char *) &pasv_addr.sin_port;
1387 
1388 #define UC(b) (((int) b) & 0xff)
1389 
1390 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1391 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1392 	return;
1393 
1394 pasv_error:
1395 	(void) close(pdata);
1396 	pdata = -1;
1397 	perror_reply(425, "Can't open passive connection");
1398 	return;
1399 }
1400 
1401 /*
1402  * Generate unique name for file with basename "local".
1403  * The file named "local" is already known to exist.
1404  * Generates failure reply on error.
1405  */
1406 static char *
1407 gunique(local)
1408 	char *local;
1409 {
1410 	static char new[MAXPATHLEN];
1411 	struct stat st;
1412 	int count;
1413 	char *cp;
1414 
1415 	cp = strrchr(local, '/');
1416 	if (cp)
1417 		*cp = '\0';
1418 	if (stat(cp ? local : ".", &st) < 0) {
1419 		perror_reply(553, cp ? local : ".");
1420 		return ((char *) 0);
1421 	}
1422 	if (cp)
1423 		*cp = '/';
1424 	(void) strcpy(new, local);
1425 	cp = new + strlen(new);
1426 	*cp++ = '.';
1427 	for (count = 1; count < 100; count++) {
1428 		(void)sprintf(cp, "%d", count);
1429 		if (stat(new, &st) < 0)
1430 			return (new);
1431 	}
1432 	reply(452, "Unique file name cannot be created.");
1433 	return (NULL);
1434 }
1435 
1436 /*
1437  * Format and send reply containing system error number.
1438  */
1439 void
1440 perror_reply(code, string)
1441 	int code;
1442 	char *string;
1443 {
1444 
1445 	reply(code, "%s: %s.", string, strerror(errno));
1446 }
1447 
1448 static char *onefile[] = {
1449 	"",
1450 	0
1451 };
1452 
1453 void
1454 send_file_list(whichf)
1455 	char *whichf;
1456 {
1457 	struct stat st;
1458 	DIR *dirp = NULL;
1459 	struct dirent *dir;
1460 	FILE *dout = NULL;
1461 	char **dirlist, *dirname;
1462 	int simple = 0;
1463 	int freeglob = 0;
1464 	glob_t gl;
1465 
1466 	if (strpbrk(whichf, "~{[*?") != NULL) {
1467 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1468 
1469 		memset(&gl, 0, sizeof(gl));
1470 		freeglob = 1;
1471 		if (glob(whichf, flags, 0, &gl)) {
1472 			reply(550, "not found");
1473 			goto out;
1474 		} else if (gl.gl_pathc == 0) {
1475 			errno = ENOENT;
1476 			perror_reply(550, whichf);
1477 			goto out;
1478 		}
1479 		dirlist = gl.gl_pathv;
1480 	} else {
1481 		onefile[0] = whichf;
1482 		dirlist = onefile;
1483 		simple = 1;
1484 	}
1485 
1486 	if (setjmp(urgcatch)) {
1487 		transflag = 0;
1488 		goto out;
1489 	}
1490 	while (dirname = *dirlist++) {
1491 		if (stat(dirname, &st) < 0) {
1492 			/*
1493 			 * If user typed "ls -l", etc, and the client
1494 			 * used NLST, do what the user meant.
1495 			 */
1496 			if (dirname[0] == '-' && *dirlist == NULL &&
1497 			    transflag == 0) {
1498 				retrieve("/bin/ls %s", dirname);
1499 				goto out;
1500 			}
1501 			perror_reply(550, whichf);
1502 			if (dout != NULL) {
1503 				(void) fclose(dout);
1504 				transflag = 0;
1505 				data = -1;
1506 				pdata = -1;
1507 			}
1508 			goto out;
1509 		}
1510 
1511 		if (S_ISREG(st.st_mode)) {
1512 			if (dout == NULL) {
1513 				dout = dataconn("file list", (off_t)-1, "w");
1514 				if (dout == NULL)
1515 					goto out;
1516 				transflag++;
1517 			}
1518 			fprintf(dout, "%s%s\n", dirname,
1519 				type == TYPE_A ? "\r" : "");
1520 			byte_count += strlen(dirname) + 1;
1521 			continue;
1522 		} else if (!S_ISDIR(st.st_mode))
1523 			continue;
1524 
1525 		if ((dirp = opendir(dirname)) == NULL)
1526 			continue;
1527 
1528 		while ((dir = readdir(dirp)) != NULL) {
1529 			char nbuf[MAXPATHLEN];
1530 
1531 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1532 				continue;
1533 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1534 			    dir->d_namlen == 2)
1535 				continue;
1536 
1537 			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
1538 
1539 			/*
1540 			 * We have to do a stat to insure it's
1541 			 * not a directory or special file.
1542 			 */
1543 			if (simple || (stat(nbuf, &st) == 0 &&
1544 			    S_ISREG(st.st_mode))) {
1545 				if (dout == NULL) {
1546 					dout = dataconn("file list", (off_t)-1,
1547 						"w");
1548 					if (dout == NULL)
1549 						goto out;
1550 					transflag++;
1551 				}
1552 				if (nbuf[0] == '.' && nbuf[1] == '/')
1553 					fprintf(dout, "%s%s\n", &nbuf[2],
1554 						type == TYPE_A ? "\r" : "");
1555 				else
1556 					fprintf(dout, "%s%s\n", nbuf,
1557 						type == TYPE_A ? "\r" : "");
1558 				byte_count += strlen(nbuf) + 1;
1559 			}
1560 		}
1561 		(void) closedir(dirp);
1562 	}
1563 
1564 	if (dout == NULL)
1565 		reply(550, "No files found.");
1566 	else if (ferror(dout) != 0)
1567 		perror_reply(550, "Data connection");
1568 	else
1569 		reply(226, "Transfer complete.");
1570 
1571 	transflag = 0;
1572 	if (dout != NULL)
1573 		(void) fclose(dout);
1574 	data = -1;
1575 	pdata = -1;
1576 out:
1577 	if (freeglob) {
1578 		freeglob = 0;
1579 		globfree(&gl);
1580 	}
1581 }
1582 
1583 #ifdef SETPROCTITLE
1584 /*
1585  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
1586  * Warning, since this is usually started from inetd.conf, it often doesn't
1587  * have much of an environment or arglist to overwrite.
1588  */
1589 void
1590 #if __STDC__
1591 setproctitle(const char *fmt, ...)
1592 #else
1593 setproctitle(fmt, va_alist)
1594 	char *fmt;
1595         va_dcl
1596 #endif
1597 {
1598 	int i;
1599 	va_list ap;
1600 	char *p, *bp, ch;
1601 	char buf[LINE_MAX];
1602 
1603 #if __STDC__
1604 	va_start(ap, fmt);
1605 #else
1606 	va_start(ap);
1607 #endif
1608 	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
1609 
1610 	/* make ps print our process name */
1611 	p = Argv[0];
1612 	*p++ = '-';
1613 
1614 	i = strlen(buf);
1615 	if (i > LastArgv - p - 2) {
1616 		i = LastArgv - p - 2;
1617 		buf[i] = '\0';
1618 	}
1619 	bp = buf;
1620 	while (ch = *bp++)
1621 		if (ch != '\n' && ch != '\r')
1622 			*p++ = ch;
1623 	while (p < LastArgv)
1624 		*p++ = ' ';
1625 }
1626 #endif /* SETPROCTITLE */
1627