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