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