xref: /freebsd/libexec/ftpd/ftpd.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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  *	$Id: ftpd.c,v 1.41 1997/07/24 09:26:12 davidn Exp $
34  */
35 
36 #if 0
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 #endif
43 
44 #if 0
45 #ifndef lint
46 static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
47 #endif /* not lint */
48 #endif
49 
50 /*
51  * FTP server.
52  */
53 #include <sys/param.h>
54 #include <sys/stat.h>
55 #include <sys/ioctl.h>
56 #include <sys/socket.h>
57 #include <sys/wait.h>
58 #include <sys/mman.h>
59 
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #include <netinet/tcp.h>
64 
65 #define	FTP_NAMES
66 #include <arpa/ftp.h>
67 #include <arpa/inet.h>
68 #include <arpa/telnet.h>
69 
70 #include <ctype.h>
71 #include <dirent.h>
72 #include <err.h>
73 #include <errno.h>
74 #include <fcntl.h>
75 #include <glob.h>
76 #include <limits.h>
77 #include <netdb.h>
78 #include <pwd.h>
79 #include <grp.h>
80 #include <setjmp.h>
81 #include <signal.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
85 #include <syslog.h>
86 #include <time.h>
87 #include <unistd.h>
88 #include <libutil.h>
89 #ifdef	LOGIN_CAP
90 #include <login_cap.h>
91 #endif
92 
93 #ifdef	SKEY
94 #include <skey.h>
95 #endif
96 
97 #include "pathnames.h"
98 #include "extern.h"
99 
100 #if __STDC__
101 #include <stdarg.h>
102 #else
103 #include <varargs.h>
104 #endif
105 
106 #ifdef	INTERNAL_LS
107 static char version[] = "Version 6.00LS";
108 #undef main
109 #else
110 static char version[] = "Version 6.00";
111 #endif
112 
113 extern	off_t restart_point;
114 extern	char cbuf[];
115 
116 struct	sockaddr_in server_addr;
117 struct	sockaddr_in ctrl_addr;
118 struct	sockaddr_in data_source;
119 struct	sockaddr_in data_dest;
120 struct	sockaddr_in his_addr;
121 struct	sockaddr_in pasv_addr;
122 
123 int	daemon_mode;
124 int	data;
125 jmp_buf	errcatch, urgcatch;
126 int	logged_in;
127 struct	passwd *pw;
128 int	debug;
129 int	timeout = 900;    /* timeout after 15 minutes of inactivity */
130 int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
131 int	logging;
132 int	restricted_data_ports = 1;
133 int	paranoid = 1;	  /* be extra careful about security */
134 int	anon_only = 0;    /* Only anonymous ftp allowed */
135 int	guest;
136 int	dochroot;
137 int	stats;
138 int	statfd = -1;
139 int	type;
140 int	form;
141 int	stru;			/* avoid C keyword */
142 int	mode;
143 int	usedefault = 1;		/* for data transfers */
144 int	pdata = -1;		/* for passive mode */
145 sig_atomic_t transflag;
146 off_t	file_size;
147 off_t	byte_count;
148 #if !defined(CMASK) || CMASK == 0
149 #undef CMASK
150 #define CMASK 027
151 #endif
152 int	defumask = CMASK;		/* default umask value */
153 char	tmpline[7];
154 char	*hostname;
155 #ifdef VIRTUAL_HOSTING
156 char	*ftpuser;
157 
158 static struct ftphost {
159 	struct ftphost	*next;
160 	struct in_addr	hostaddr;
161 	char		*hostname;
162 	char		*anonuser;
163 	char		*statfile;
164 	char		*welcome;
165 	char		*loginmsg;
166 } *thishost, *firsthost;
167 
168 #endif
169 char	remotehost[MAXHOSTNAMELEN];
170 char	*ident = NULL;
171 
172 static char ttyline[20];
173 char	*tty = ttyline;		/* for klogin */
174 
175 #ifdef KERBEROS
176 int	 klogin __P((struct passwd *, char *, char *, char *));
177 #endif
178 
179 struct	in_addr bind_address;
180 char	*pid_file = NULL;
181 
182 #if defined(KERBEROS)
183 int	notickets = 1;
184 int	noticketsdontcomplain = 1;
185 char	*krbtkfile_env = NULL;
186 #endif
187 
188 /*
189  * Timeout intervals for retrying connections
190  * to hosts that don't accept PORT cmds.  This
191  * is a kludge, but given the problems with TCP...
192  */
193 #define	SWAITMAX	90	/* wait at most 90 seconds */
194 #define	SWAITINT	5	/* interval between retries */
195 
196 int	swaitmax = SWAITMAX;
197 int	swaitint = SWAITINT;
198 
199 #ifdef SETPROCTITLE
200 #ifdef OLD_SETPROCTITLE
201 char	**Argv = NULL;		/* pointer to argument vector */
202 char	*LastArgv = NULL;	/* end of argv */
203 #endif /* OLD_SETPROCTITLE */
204 char	proctitle[LINE_MAX];	/* initial part of title */
205 #endif /* SETPROCTITLE */
206 
207 #ifdef SKEY
208 int	pwok = 0;
209 char	addr_string[20];	/* XXX */
210 #endif
211 
212 #define LOGCMD(cmd, file) \
213 	if (logging > 1) \
214 	    syslog(LOG_INFO,"%s %s%s", cmd, \
215 		*(file) == '/' ? "" : curdir(), file);
216 #define LOGCMD2(cmd, file1, file2) \
217 	 if (logging > 1) \
218 	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
219 		*(file1) == '/' ? "" : curdir(), file1, \
220 		*(file2) == '/' ? "" : curdir(), file2);
221 #define LOGBYTES(cmd, file, cnt) \
222 	if (logging > 1) { \
223 		if (cnt == (off_t)-1) \
224 		    syslog(LOG_INFO,"%s %s%s", cmd, \
225 			*(file) == '/' ? "" : curdir(), file); \
226 		else \
227 		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
228 			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
229 	}
230 
231 #ifdef VIRTUAL_HOSTING
232 static void	 inithosts __P((void));
233 static void	selecthost __P((struct in_addr *));
234 #endif
235 static void	 ack __P((char *));
236 static void	 myoob __P((int));
237 static int	 checkuser __P((char *, char *));
238 static FILE	*dataconn __P((char *, off_t, char *));
239 static void	 dolog __P((struct sockaddr_in *));
240 static char	*curdir __P((void));
241 static void	 end_login __P((void));
242 static FILE	*getdatasock __P((char *));
243 static char	*gunique __P((char *));
244 static void	 lostconn __P((int));
245 static int	 receive_data __P((FILE *, FILE *));
246 static void	 send_data __P((FILE *, FILE *, off_t, off_t, int));
247 static struct passwd *
248 		 sgetpwnam __P((char *));
249 static char	*sgetsave __P((char *));
250 static void	 reapchild __P((int));
251 static void      logxfer __P((char *, long, long));
252 
253 static char *
254 curdir()
255 {
256 	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */
257 
258 	if (getcwd(path, sizeof(path)-2) == NULL)
259 		return ("");
260 	if (path[1] != '\0')		/* special case for root dir. */
261 		strcat(path, "/");
262 	/* For guest account, skip / since it's chrooted */
263 	return (guest ? path+1 : path);
264 }
265 
266 int
267 main(argc, argv, envp)
268 	int argc;
269 	char *argv[];
270 	char **envp;
271 {
272 	int addrlen, ch, on = 1, tos;
273 	char *cp, line[LINE_MAX];
274 	FILE *fd;
275 
276 	tzset();		/* in case no timezone database in ~ftp */
277 
278 #ifdef OLD_SETPROCTITLE
279 	/*
280 	 *  Save start and extent of argv for setproctitle.
281 	 */
282 	Argv = argv;
283 	while (*envp)
284 		envp++;
285 	LastArgv = envp[-1] + strlen(envp[-1]);
286 #endif /* OLD_SETPROCTITLE */
287 
288 
289 	bind_address.s_addr = htonl(INADDR_ANY);
290 	while ((ch = getopt(argc, argv, "AdlDSURt:T:u:va:p:")) != -1) {
291 		switch (ch) {
292 		case 'D':
293 			daemon_mode++;
294 			break;
295 
296 		case 'd':
297 			debug++;
298 			break;
299 
300 		case 'l':
301 			logging++;	/* > 1 == extra logging */
302 			break;
303 
304 		case 'R':
305 			paranoid = 0;
306 			break;
307 
308 		case 'S':
309 			stats++;
310 			break;
311 
312 		case 'T':
313 			maxtimeout = atoi(optarg);
314 			if (timeout > maxtimeout)
315 				timeout = maxtimeout;
316 			break;
317 
318 		case 't':
319 			timeout = atoi(optarg);
320 			if (maxtimeout < timeout)
321 				maxtimeout = timeout;
322 			break;
323 
324 		case 'U':
325 			restricted_data_ports = 0;
326 			break;
327 
328 		case 'a':
329 			if (!inet_aton(optarg, &bind_address))
330 				errx(1, "invalid address for -a");
331 			break;
332 
333 		case 'p':
334 			pid_file = optarg;
335 			break;
336 
337 		case 'u':
338 		    {
339 			long val = 0;
340 
341 			val = strtol(optarg, &optarg, 8);
342 			if (*optarg != '\0' || val < 0)
343 				warnx("bad value for -u");
344 			else
345 				defumask = val;
346 			break;
347 		    }
348 		case 'A':
349 			anon_only = 1;
350 			break;
351 
352 		case 'v':
353 			debug = 1;
354 			break;
355 
356 		default:
357 			warnx("unknown flag -%c ignored", optopt);
358 			break;
359 		}
360 	}
361 
362 #ifdef VIRTUAL_HOSTING
363 	inithosts();
364 #endif
365 	(void) freopen(_PATH_DEVNULL, "w", stderr);
366 
367 	/*
368 	 * LOG_NDELAY sets up the logging connection immediately,
369 	 * necessary for anonymous ftp's that chroot and can't do it later.
370 	 */
371 	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
372 
373 	if (daemon_mode) {
374 		int ctl_sock, fd;
375 		struct servent *sv;
376 
377 		/*
378 		 * Detach from parent.
379 		 */
380 		if (daemon(1, 1) < 0) {
381 			syslog(LOG_ERR, "failed to become a daemon");
382 			exit(1);
383 		}
384 		(void) signal(SIGCHLD, reapchild);
385 		/*
386 		 * Get port number for ftp/tcp.
387 		 */
388 		sv = getservbyname("ftp", "tcp");
389 		if (sv == NULL) {
390 			syslog(LOG_ERR, "getservbyname for ftp failed");
391 			exit(1);
392 		}
393 		/*
394 		 * Open a socket, bind it to the FTP port, and start
395 		 * listening.
396 		 */
397 		ctl_sock = socket(AF_INET, SOCK_STREAM, 0);
398 		if (ctl_sock < 0) {
399 			syslog(LOG_ERR, "control socket: %m");
400 			exit(1);
401 		}
402 		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,
403 		    (char *)&on, sizeof(on)) < 0)
404 			syslog(LOG_ERR, "control setsockopt: %m");;
405 		server_addr.sin_family = AF_INET;
406 		server_addr.sin_addr = bind_address;
407 		server_addr.sin_port = sv->s_port;
408 		if (bind(ctl_sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) {
409 			syslog(LOG_ERR, "control bind: %m");
410 			exit(1);
411 		}
412 		if (listen(ctl_sock, 32) < 0) {
413 			syslog(LOG_ERR, "control listen: %m");
414 			exit(1);
415 		}
416 		/*
417 		 * Atomically write process ID
418 		 */
419 		if (pid_file)
420 		{
421 			int fd;
422 			char buf[20];
423 
424 			fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC
425 				| O_NONBLOCK | O_EXLOCK, 0644);
426 			if (fd < 0)
427 				if (errno == EAGAIN)
428 					errx(1, "%s: file locked", pid_file);
429 				else
430 					err(1, "%s", pid_file);
431 			snprintf(buf, sizeof(buf),
432 				"%lu\n", (unsigned long) getpid());
433 			if (write(fd, buf, strlen(buf)) < 0)
434 				err(1, "%s: write", pid_file);
435 			/* Leave the pid file open and locked */
436 		}
437 		/*
438 		 * Loop forever accepting connection requests and forking off
439 		 * children to handle them.
440 		 */
441 		while (1) {
442 			addrlen = sizeof(his_addr);
443 			fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen);
444 			if (fork() == 0) {
445 				/* child */
446 				(void) dup2(fd, 0);
447 				(void) dup2(fd, 1);
448 				close(ctl_sock);
449 				break;
450 			}
451 			close(fd);
452 		}
453 	} else {
454 		addrlen = sizeof(his_addr);
455 		if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
456 			syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
457 			exit(1);
458 		}
459 	}
460 
461 	(void) signal(SIGCHLD, SIG_IGN);
462 	(void) signal(SIGPIPE, lostconn);
463 	if ((int)signal(SIGURG, myoob) < 0)
464 		syslog(LOG_ERR, "signal: %m");
465 
466 #ifdef SKEY
467 	strncpy(addr_string, inet_ntoa(his_addr.sin_addr), sizeof(addr_string));
468 #endif
469 	addrlen = sizeof(ctrl_addr);
470 	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
471 		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
472 		exit(1);
473 	}
474 #ifdef VIRTUAL_HOSTING
475 	/* select our identity from virtual host table */
476 	selecthost(&ctrl_addr.sin_addr);
477 #endif
478 #ifdef IP_TOS
479 	tos = IPTOS_LOWDELAY;
480 	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
481 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
482 #endif
483 	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
484 
485 	/* set this here so klogin can use it... */
486 	(void)sprintf(ttyline, "ftp%d", getpid());
487 
488 	/* Try to handle urgent data inline */
489 #ifdef SO_OOBINLINE
490 	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
491 		syslog(LOG_ERR, "setsockopt: %m");
492 #endif
493 
494 #ifdef	F_SETOWN
495 	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
496 		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
497 #endif
498 	dolog(&his_addr);
499 	/*
500 	 * Set up default state
501 	 */
502 	data = -1;
503 	type = TYPE_A;
504 	form = FORM_N;
505 	stru = STRU_F;
506 	mode = MODE_S;
507 	tmpline[0] = '\0';
508 
509 	/* If logins are disabled, print out the message. */
510 	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
511 		while (fgets(line, sizeof(line), fd) != NULL) {
512 			if ((cp = strchr(line, '\n')) != NULL)
513 				*cp = '\0';
514 			lreply(530, "%s", line);
515 		}
516 		(void) fflush(stdout);
517 		(void) fclose(fd);
518 		reply(530, "System not available.");
519 		exit(0);
520 	}
521 #ifdef VIRTUAL_HOSTING
522 	if ((fd = fopen(thishost->welcome, "r")) != NULL) {
523 #else
524 	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
525 #endif
526 		while (fgets(line, sizeof(line), fd) != NULL) {
527 			if ((cp = strchr(line, '\n')) != NULL)
528 				*cp = '\0';
529 			lreply(220, "%s", line);
530 		}
531 		(void) fflush(stdout);
532 		(void) fclose(fd);
533 		/* reply(220,) must follow */
534 	}
535 #ifndef VIRTUAL_HOSTING
536 	if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL)
537 		fatal("Ran out of memory.");
538 	(void) gethostname(hostname, MAXHOSTNAMELEN);
539 #endif
540 	reply(220, "%s FTP server (%s) ready.", hostname, version);
541 	(void) setjmp(errcatch);
542 	for (;;)
543 		(void) yyparse();
544 	/* NOTREACHED */
545 }
546 
547 static void
548 lostconn(signo)
549 	int signo;
550 {
551 
552 	if (debug)
553 		syslog(LOG_DEBUG, "lost connection");
554 	dologout(-1);
555 }
556 
557 #ifdef VIRTUAL_HOSTING
558 /*
559  * read in virtual host tables (if they exist)
560  */
561 
562 static void
563 inithosts()
564 {
565 	FILE *fp;
566 	char *cp;
567 	struct hostent *hp;
568 	struct ftphost *hrp, *lhrp;
569 	char line[1024];
570 
571 	/*
572 	 * Fill in the default host information
573 	 */
574 	if (gethostname(line, sizeof(line)) < 0)
575 		line[0] = '\0';
576 	if ((hrp = malloc(sizeof(struct ftphost))) == NULL ||
577 	    (hrp->hostname = strdup(line)) == NULL)
578 		fatal("Ran out of memory.");
579 	memset(&hrp->hostaddr, 0, sizeof hrp->hostaddr);
580 	if ((hp = gethostbyname(hrp->hostname)) != NULL)
581 		(void) memcpy(&hrp->hostaddr,
582 			      hp->h_addr_list[0],
583 			      sizeof(hrp->hostaddr));
584 	hrp->statfile = _PATH_FTPDSTATFILE;
585 	hrp->welcome  = _PATH_FTPWELCOME;
586 	hrp->loginmsg = _PATH_FTPLOGINMESG;
587 	hrp->anonuser = "ftp";
588 	hrp->next = NULL;
589 	thishost = firsthost = lhrp = hrp;
590 	if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) {
591 		while (fgets(line, sizeof(line), fp) != NULL) {
592 			int	i;
593 
594 			if ((cp = strchr(line, '\n')) == NULL) {
595 				/* ignore long lines */
596 				while (fgets(line, sizeof(line), fp) != NULL &&
597 					strchr(line, '\n') == NULL)
598 					;
599 				continue;
600 			}
601 			*cp = '\0';
602 			cp = strtok(line, " \t");
603 			/* skip comments and empty lines */
604 			if (cp == NULL || line[0] == '#')
605 				continue;
606 			/* first, try a standard gethostbyname() */
607 			if ((hp = gethostbyname(cp)) == NULL)
608 				continue;
609 			for (hrp = firsthost; hrp != NULL; hrp = hrp->next) {
610 				if (memcmp(&hrp->hostaddr,
611 					   hp->h_addr_list[0],
612 					   sizeof(hrp->hostaddr)) == 0)
613 					break;
614 			}
615 			if (hrp == NULL) {
616 				if ((hrp = malloc(sizeof(struct ftphost))) == NULL)
617 					continue;
618 				/* defaults */
619 				hrp->statfile = _PATH_FTPDSTATFILE;
620 				hrp->welcome  = _PATH_FTPWELCOME;
621 				hrp->loginmsg = _PATH_FTPLOGINMESG;
622 				hrp->anonuser = "ftp";
623 				hrp->next     = NULL;
624 				lhrp->next = hrp;
625 				lhrp = hrp;
626 			}
627 			(void) memcpy(&hrp->hostaddr,
628 				      hp->h_addr_list[0],
629 				      sizeof(hrp->hostaddr));
630 			/*
631 			 * determine hostname to use.
632 			 * force defined name if it is a valid alias
633 			 * otherwise fallback to primary hostname
634 			 */
635 			if ((hp = gethostbyaddr((char*)&hrp->hostaddr,
636 						sizeof(hrp->hostaddr),
637 						AF_INET)) != NULL) {
638 				if (strcmp(cp, hp->h_name) != 0) {
639 					if (hp->h_aliases == NULL)
640 						cp = hp->h_name;
641 					else {
642 						i = 0;
643 						while (hp->h_aliases[i] &&
644 						       strcmp(cp, hp->h_aliases[i]) != 0)
645 							++i;
646 						if (hp->h_aliases[i] == NULL)
647 							cp = hp->h_name;
648 					}
649 				}
650 			}
651 			hrp->hostname = strdup(cp);
652 			/* ok, now we now peel off the rest */
653 			i = 0;
654 			while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) {
655 				if (*cp != '-' && (cp = strdup(cp)) != NULL) {
656 					switch (i) {
657 					case 0:	/* anon user permissions */
658 						hrp->anonuser = cp;
659 						break;
660 					case 1: /* statistics file */
661 						hrp->statfile = cp;
662 						break;
663 					case 2: /* welcome message */
664 						hrp->welcome  = cp;
665 						break;
666 					case 3: /* login message */
667 						hrp->loginmsg = cp;
668 						break;
669 					}
670 				}
671 				++i;
672 			}
673 		}
674 		(void) fclose(fp);
675 	}
676 }
677 
678 static void
679 selecthost(a)
680 	struct in_addr *a;
681 {
682 	struct ftphost	*hrp;
683 
684 	hrp = thishost = firsthost;	/* default */
685 	while (hrp != NULL) {
686 		if (memcmp(a, &hrp->hostaddr, sizeof(hrp->hostaddr)) == 0) {
687 			thishost = hrp;
688 			break;
689 		}
690 		hrp = hrp->next;
691 	}
692 	/* setup static variables as appropriate */
693 	hostname = thishost->hostname;
694 	ftpuser = thishost->anonuser;
695 }
696 #endif
697 
698 /*
699  * Helper function for sgetpwnam().
700  */
701 static char *
702 sgetsave(s)
703 	char *s;
704 {
705 	char *new = malloc((unsigned) strlen(s) + 1);
706 
707 	if (new == NULL) {
708 		perror_reply(421, "Local resource failure: malloc");
709 		dologout(1);
710 		/* NOTREACHED */
711 	}
712 	(void) strcpy(new, s);
713 	return (new);
714 }
715 
716 /*
717  * Save the result of a getpwnam.  Used for USER command, since
718  * the data returned must not be clobbered by any other command
719  * (e.g., globbing).
720  */
721 static struct passwd *
722 sgetpwnam(name)
723 	char *name;
724 {
725 	static struct passwd save;
726 	struct passwd *p;
727 
728 	if ((p = getpwnam(name)) == NULL)
729 		return (p);
730 	if (save.pw_name) {
731 		free(save.pw_name);
732 		free(save.pw_passwd);
733 		free(save.pw_gecos);
734 		free(save.pw_dir);
735 		free(save.pw_shell);
736 	}
737 	save = *p;
738 	save.pw_name = sgetsave(p->pw_name);
739 	save.pw_passwd = sgetsave(p->pw_passwd);
740 	save.pw_gecos = sgetsave(p->pw_gecos);
741 	save.pw_dir = sgetsave(p->pw_dir);
742 	save.pw_shell = sgetsave(p->pw_shell);
743 	return (&save);
744 }
745 
746 static int login_attempts;	/* number of failed login attempts */
747 static int askpasswd;		/* had user command, ask for passwd */
748 static char curname[10];	/* current USER name */
749 
750 /*
751  * USER command.
752  * Sets global passwd pointer pw if named account exists and is acceptable;
753  * sets askpasswd if a PASS command is expected.  If logged in previously,
754  * need to reset state.  If name is "ftp" or "anonymous", the name is not in
755  * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
756  * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
757  * requesting login privileges.  Disallow anyone who does not have a standard
758  * shell as returned by getusershell().  Disallow anyone mentioned in the file
759  * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
760  */
761 void
762 user(name)
763 	char *name;
764 {
765 	char *cp, *shell;
766 
767 	if (logged_in) {
768 		if (guest) {
769 			reply(530, "Can't change user from guest login.");
770 			return;
771 		} else if (dochroot) {
772 			reply(530, "Can't change user from chroot user.");
773 			return;
774 		}
775 		end_login();
776 	}
777 
778 	guest = 0;
779 	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
780 		if (checkuser(_PATH_FTPUSERS, "ftp") ||
781 		    checkuser(_PATH_FTPUSERS, "anonymous"))
782 			reply(530, "User %s access denied.", name);
783 #ifdef VIRTUAL_HOSTING
784 		else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) {
785 #else
786 		else if ((pw = sgetpwnam("ftp")) != NULL) {
787 #endif
788 			guest = 1;
789 			askpasswd = 1;
790 			reply(331,
791 			"Guest login ok, send your email address as password.");
792 		} else
793 			reply(530, "User %s unknown.", name);
794 		if (!askpasswd && logging)
795 			syslog(LOG_NOTICE,
796 			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
797 		return;
798 	}
799 	if (anon_only != 0) {
800 		reply(530, "Sorry, only anonymous ftp allowed.");
801 		return;
802 	}
803 
804 	if ((pw = sgetpwnam(name))) {
805 		if ((shell = pw->pw_shell) == NULL || *shell == 0)
806 			shell = _PATH_BSHELL;
807 		while ((cp = getusershell()) != NULL)
808 			if (strcmp(cp, shell) == 0)
809 				break;
810 		endusershell();
811 
812 		if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {
813 			reply(530, "User %s access denied.", name);
814 			if (logging)
815 				syslog(LOG_NOTICE,
816 				    "FTP LOGIN REFUSED FROM %s, %s",
817 				    remotehost, name);
818 			pw = (struct passwd *) NULL;
819 			return;
820 		}
821 	}
822 	if (logging)
823 		strncpy(curname, name, sizeof(curname)-1);
824 #ifdef SKEY
825 	pwok = skeyaccess(name, NULL, remotehost, addr_string);
826 	reply(331, "%s", skey_challenge(name, pw, pwok));
827 #else
828 	reply(331, "Password required for %s.", name);
829 #endif
830 	askpasswd = 1;
831 	/*
832 	 * Delay before reading passwd after first failed
833 	 * attempt to slow down passwd-guessing programs.
834 	 */
835 	if (login_attempts)
836 		sleep((unsigned) login_attempts);
837 }
838 
839 /*
840  * Check if a user is in the file "fname"
841  */
842 static int
843 checkuser(fname, name)
844 	char *fname;
845 	char *name;
846 {
847 	FILE *fd;
848 	int found = 0;
849 	char *p, line[BUFSIZ];
850 
851 	if ((fd = fopen(fname, "r")) != NULL) {
852 		while (!found && fgets(line, sizeof(line), fd) != NULL)
853 			if ((p = strchr(line, '\n')) != NULL) {
854 				*p = '\0';
855 				if (line[0] == '#')
856 					continue;
857 				/*
858 				 * if first chr is '@', check group membership
859 				 */
860 				if (line[0] == '@') {
861 					int i = 0;
862 					struct group *grp;
863 
864 					if ((grp = getgrnam(line+1)) == NULL)
865 						continue;
866 					while (!found && grp->gr_mem[i])
867 						found = strcmp(name,
868 							grp->gr_mem[i++])
869 							== 0;
870 				}
871 				/*
872 				 * Otherwise, just check for username match
873 				 */
874 				else
875 					found = strcmp(line, name) == 0;
876 			}
877 		(void) fclose(fd);
878 	}
879 	return (found);
880 }
881 
882 /*
883  * Terminate login as previous user, if any, resetting state;
884  * used when USER command is given or login fails.
885  */
886 static void
887 end_login()
888 {
889 
890 	(void) seteuid((uid_t)0);
891 	if (logged_in)
892 		ftpd_logwtmp(ttyline, "", "");
893 	pw = NULL;
894 #ifdef	LOGIN_CAP
895 	setusercontext(NULL, getpwuid(0), (uid_t)0,
896 		       LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
897 #endif
898 	logged_in = 0;
899 	guest = 0;
900 	dochroot = 0;
901 }
902 
903 void
904 pass(passwd)
905 	char *passwd;
906 {
907 	int rval;
908 	FILE *fd;
909 #ifdef	LOGIN_CAP
910 	login_cap_t *lc = NULL;
911 #endif
912 	static char homedir[MAXPATHLEN];
913 
914 	if (logged_in || askpasswd == 0) {
915 		reply(503, "Login with USER first.");
916 		return;
917 	}
918 	askpasswd = 0;
919 	if (!guest) {		/* "ftp" is only account allowed no password */
920 		if (pw == NULL) {
921 			rval = 1;	/* failure below */
922 			goto skip;
923 		}
924 #if defined(KERBEROS)
925 		rval = klogin(pw, "", hostname, passwd);
926 		if (rval == 0)
927 			goto skip;
928 #endif
929 #ifdef SKEY
930 		rval = strcmp(skey_crypt(passwd, pw->pw_passwd, pw, pwok),
931 			      pw->pw_passwd);
932 		pwok = 0;
933 #else
934 		rval = strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd);
935 #endif
936 		/* The strcmp does not catch null passwords! */
937 		if (*pw->pw_passwd == '\0' ||
938 		    (pw->pw_expire && time(NULL) >= pw->pw_expire))
939 			rval = 1;	/* failure */
940 skip:
941 		/*
942 		 * If rval == 1, the user failed the authentication check
943 		 * above.  If rval == 0, either Kerberos or local authentication
944 		 * succeeded.
945 		 */
946 		if (rval) {
947 			reply(530, "Login incorrect.");
948 			if (logging)
949 				syslog(LOG_NOTICE,
950 				    "FTP LOGIN FAILED FROM %s, %s",
951 				    remotehost, curname);
952 			pw = NULL;
953 			if (login_attempts++ >= 5) {
954 				syslog(LOG_NOTICE,
955 				    "repeated login failures from %s",
956 				    remotehost);
957 				exit(0);
958 			}
959 			return;
960 		}
961 	}
962 	login_attempts = 0;		/* this time successful */
963 	if (setegid((gid_t)pw->pw_gid) < 0) {
964 		reply(550, "Can't set gid.");
965 		return;
966 	}
967 	/* May be overridden by login.conf */
968 	(void) umask(defumask);
969 #ifdef	LOGIN_CAP
970 	if ((lc = login_getpwclass(pw)) != NULL) {
971 		char	remote_ip[MAXHOSTNAMELEN];
972 
973 		strncpy(remote_ip, inet_ntoa(his_addr.sin_addr),
974 			sizeof(remote_ip) - 1);
975 		remote_ip[sizeof(remote_ip) - 1] = 0;
976 		if (!auth_hostok(lc, remotehost, remote_ip)) {
977 			syslog(LOG_INFO|LOG_AUTH,
978 			    "FTP LOGIN FAILED (HOST) as %s: permission denied.",
979 			    pw->pw_name);
980 			reply(530, "Permission denied.\n");
981 			pw = NULL;
982 			return;
983 		}
984 		if (!auth_timeok(lc, time(NULL))) {
985 			reply(530, "Login not available right now.\n");
986 			pw = NULL;
987 			return;
988 		}
989 	}
990 	setusercontext(lc, pw, (uid_t)0,
991 	LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK);
992 #else
993 	(void) initgroups(pw->pw_name, pw->pw_gid);
994 #endif
995 
996 	/* open wtmp before chroot */
997 	ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
998 	logged_in = 1;
999 
1000 	if (guest && stats && statfd < 0)
1001 #ifdef VIRTUAL_HOSTING
1002 		if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0)
1003 #else
1004 		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
1005 #endif
1006 			stats = 0;
1007 
1008 	dochroot =
1009 #ifdef	LOGIN_CAP	/* Allow login.conf configuration as well */
1010 		login_getcapbool(lc, "ftp-chroot", 0) ||
1011 #endif
1012 		checkuser(_PATH_FTPCHROOT, pw->pw_name);
1013 	if (guest) {
1014 		/*
1015 		 * We MUST do a chdir() after the chroot. Otherwise
1016 		 * the old current directory will be accessible as "."
1017 		 * outside the new root!
1018 		 */
1019 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1020 			reply(550, "Can't set guest privileges.");
1021 			goto bad;
1022 		}
1023 	} else if (dochroot) {
1024 		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
1025 			reply(550, "Can't change root.");
1026 			goto bad;
1027 		}
1028 	} else if (chdir(pw->pw_dir) < 0) {
1029 		if (chdir("/") < 0) {
1030 			reply(530, "User %s: can't change directory to %s.",
1031 			    pw->pw_name, pw->pw_dir);
1032 			goto bad;
1033 		} else
1034 			lreply(230, "No directory! Logging in with home=/");
1035 	}
1036 	if (seteuid((uid_t)pw->pw_uid) < 0) {
1037 		reply(550, "Can't set uid.");
1038 		goto bad;
1039 	}
1040 
1041 	/*
1042 	 * Set home directory so that use of ~ (tilde) works correctly.
1043 	 */
1044 	if (getcwd(homedir, MAXPATHLEN) != NULL)
1045 		setenv("HOME", homedir, 1);
1046 
1047 	/*
1048 	 * Display a login message, if it exists.
1049 	 * N.B. reply(230,) must follow the message.
1050 	 */
1051 #ifdef VIRTUAL_HOSTING
1052 	if ((fd = fopen(thishost->loginmsg, "r")) != NULL) {
1053 #else
1054 	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
1055 #endif
1056 		char *cp, line[LINE_MAX];
1057 
1058 		while (fgets(line, sizeof(line), fd) != NULL) {
1059 			if ((cp = strchr(line, '\n')) != NULL)
1060 				*cp = '\0';
1061 			lreply(230, "%s", line);
1062 		}
1063 		(void) fflush(stdout);
1064 		(void) fclose(fd);
1065 	}
1066 	if (guest) {
1067 		if (ident != NULL)
1068 			free(ident);
1069 		ident = strdup(passwd);
1070 		if (ident == NULL)
1071 			fatal("Ran out of memory.");
1072 
1073 		reply(230, "Guest login ok, access restrictions apply.");
1074 #ifdef SETPROCTITLE
1075 #ifdef VIRTUAL_HOSTING
1076 		if (thishost != firsthost)
1077 			snprintf(proctitle, sizeof(proctitle),
1078 				 "%s: anonymous(%s)/%.*s", remotehost, hostname,
1079 				 sizeof(proctitle) - sizeof(remotehost) -
1080 				 sizeof(": anonymous/"), passwd);
1081 		else
1082 #endif
1083 			snprintf(proctitle, sizeof(proctitle),
1084 				 "%s: anonymous/%.*s", remotehost,
1085 				 sizeof(proctitle) - sizeof(remotehost) -
1086 				 sizeof(": anonymous/"), passwd);
1087 		setproctitle("%s", proctitle);
1088 #endif /* SETPROCTITLE */
1089 		if (logging)
1090 			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1091 			    remotehost, passwd);
1092 	} else {
1093 	    if (dochroot)
1094 		reply(230, "User %s logged in, access restrictions apply.",
1095 			pw->pw_name);
1096 	    else
1097 		reply(230, "User %s logged in.", pw->pw_name);
1098 
1099 #ifdef SETPROCTITLE
1100 		snprintf(proctitle, sizeof(proctitle),
1101 			 "%s: %s", remotehost, pw->pw_name);
1102 		setproctitle("%s", proctitle);
1103 #endif /* SETPROCTITLE */
1104 		if (logging)
1105 			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1106 			    remotehost, pw->pw_name);
1107 	}
1108 #ifdef	LOGIN_CAP
1109 	login_close(lc);
1110 #endif
1111 	return;
1112 bad:
1113 	/* Forget all about it... */
1114 #ifdef	LOGIN_CAP
1115 	login_close(lc);
1116 #endif
1117 	end_login();
1118 }
1119 
1120 void
1121 retrieve(cmd, name)
1122 	char *cmd, *name;
1123 {
1124 	FILE *fin, *dout;
1125 	struct stat st;
1126 	int (*closefunc) __P((FILE *));
1127 	long start;
1128 
1129 	if (cmd == 0) {
1130 		fin = fopen(name, "r"), closefunc = fclose;
1131 		st.st_size = 0;
1132 	} else {
1133 		char line[BUFSIZ];
1134 
1135 		(void) sprintf(line, cmd, name), name = line;
1136 		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1137 		st.st_size = -1;
1138 		st.st_blksize = BUFSIZ;
1139 	}
1140 	if (fin == NULL) {
1141 		if (errno != 0) {
1142 			perror_reply(550, name);
1143 			if (cmd == 0) {
1144 				LOGCMD("get", name);
1145 			}
1146 		}
1147 		return;
1148 	}
1149 	byte_count = -1;
1150 	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1151 		reply(550, "%s: not a plain file.", name);
1152 		goto done;
1153 	}
1154 	if (restart_point) {
1155 		if (type == TYPE_A) {
1156 			off_t i, n;
1157 			int c;
1158 
1159 			n = restart_point;
1160 			i = 0;
1161 			while (i++ < n) {
1162 				if ((c=getc(fin)) == EOF) {
1163 					perror_reply(550, name);
1164 					goto done;
1165 				}
1166 				if (c == '\n')
1167 					i++;
1168 			}
1169 		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
1170 			perror_reply(550, name);
1171 			goto done;
1172 		}
1173 	}
1174 	dout = dataconn(name, st.st_size, "w");
1175 	if (dout == NULL)
1176 		goto done;
1177 	time(&start);
1178 	send_data(fin, dout, st.st_blksize, st.st_size,
1179 		  restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
1180 	if (cmd == 0 && guest && stats)
1181 		logxfer(name, st.st_size, start);
1182 	(void) fclose(dout);
1183 	data = -1;
1184 	pdata = -1;
1185 done:
1186 	if (cmd == 0)
1187 		LOGBYTES("get", name, byte_count);
1188 	(*closefunc)(fin);
1189 }
1190 
1191 void
1192 store(name, mode, unique)
1193 	char *name, *mode;
1194 	int unique;
1195 {
1196 	FILE *fout, *din;
1197 	struct stat st;
1198 	int (*closefunc) __P((FILE *));
1199 
1200 	if ((unique || guest) && stat(name, &st) == 0 &&
1201 	    (name = gunique(name)) == NULL) {
1202 		LOGCMD(*mode == 'w' ? "put" : "append", name);
1203 		return;
1204 	}
1205 
1206 	if (restart_point)
1207 		mode = "r+";
1208 	fout = fopen(name, mode);
1209 	closefunc = fclose;
1210 	if (fout == NULL) {
1211 		perror_reply(553, name);
1212 		LOGCMD(*mode == 'w' ? "put" : "append", name);
1213 		return;
1214 	}
1215 	byte_count = -1;
1216 	if (restart_point) {
1217 		if (type == TYPE_A) {
1218 			off_t i, n;
1219 			int c;
1220 
1221 			n = restart_point;
1222 			i = 0;
1223 			while (i++ < n) {
1224 				if ((c=getc(fout)) == EOF) {
1225 					perror_reply(550, name);
1226 					goto done;
1227 				}
1228 				if (c == '\n')
1229 					i++;
1230 			}
1231 			/*
1232 			 * We must do this seek to "current" position
1233 			 * because we are changing from reading to
1234 			 * writing.
1235 			 */
1236 			if (fseek(fout, 0L, L_INCR) < 0) {
1237 				perror_reply(550, name);
1238 				goto done;
1239 			}
1240 		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
1241 			perror_reply(550, name);
1242 			goto done;
1243 		}
1244 	}
1245 	din = dataconn(name, (off_t)-1, "r");
1246 	if (din == NULL)
1247 		goto done;
1248 	if (receive_data(din, fout) == 0) {
1249 		if (unique)
1250 			reply(226, "Transfer complete (unique file name:%s).",
1251 			    name);
1252 		else
1253 			reply(226, "Transfer complete.");
1254 	}
1255 	(void) fclose(din);
1256 	data = -1;
1257 	pdata = -1;
1258 done:
1259 	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1260 	(*closefunc)(fout);
1261 }
1262 
1263 static FILE *
1264 getdatasock(mode)
1265 	char *mode;
1266 {
1267 	int on = 1, s, t, tries;
1268 
1269 	if (data >= 0)
1270 		return (fdopen(data, mode));
1271 	(void) seteuid((uid_t)0);
1272 	s = socket(AF_INET, SOCK_STREAM, 0);
1273 	if (s < 0)
1274 		goto bad;
1275 	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1276 	    (char *) &on, sizeof(on)) < 0)
1277 		goto bad;
1278 	/* anchor socket to avoid multi-homing problems */
1279 	data_source.sin_len = sizeof(struct sockaddr_in);
1280 	data_source.sin_family = AF_INET;
1281 	data_source.sin_addr = ctrl_addr.sin_addr;
1282 	for (tries = 1; ; tries++) {
1283 		if (bind(s, (struct sockaddr *)&data_source,
1284 		    sizeof(data_source)) >= 0)
1285 			break;
1286 		if (errno != EADDRINUSE || tries > 10)
1287 			goto bad;
1288 		sleep(tries);
1289 	}
1290 	(void) seteuid((uid_t)pw->pw_uid);
1291 #ifdef IP_TOS
1292 	on = IPTOS_THROUGHPUT;
1293 	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1294 		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1295 #endif
1296 #ifdef TCP_NOPUSH
1297 	/*
1298 	 * Turn off push flag to keep sender TCP from sending short packets
1299 	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1300 	 * to set the send buffer size as well, but that may not be desirable
1301 	 * in heavy-load situations.
1302 	 */
1303 	on = 1;
1304 	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
1305 		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1306 #endif
1307 #ifdef SO_SNDBUF
1308 	on = 65536;
1309 	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
1310 		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1311 #endif
1312 
1313 	return (fdopen(s, mode));
1314 bad:
1315 	/* Return the real value of errno (close may change it) */
1316 	t = errno;
1317 	(void) seteuid((uid_t)pw->pw_uid);
1318 	(void) close(s);
1319 	errno = t;
1320 	return (NULL);
1321 }
1322 
1323 static FILE *
1324 dataconn(name, size, mode)
1325 	char *name;
1326 	off_t size;
1327 	char *mode;
1328 {
1329 	char sizebuf[32];
1330 	FILE *file;
1331 	int retry = 0, tos;
1332 
1333 	file_size = size;
1334 	byte_count = 0;
1335 	if (size != (off_t) -1)
1336 		(void) sprintf(sizebuf, " (%qd bytes)", size);
1337 	else
1338 		(void) strcpy(sizebuf, "");
1339 	if (pdata >= 0) {
1340 		struct sockaddr_in from;
1341 		int s, fromlen = sizeof(from);
1342 		struct timeval timeout;
1343 		fd_set set;
1344 
1345 		FD_ZERO(&set);
1346 		FD_SET(pdata, &set);
1347 
1348 		timeout.tv_usec = 0;
1349 		timeout.tv_sec = 120;
1350 
1351 		if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
1352 		    (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
1353 			reply(425, "Can't open data connection.");
1354 			(void) close(pdata);
1355 			pdata = -1;
1356 			return (NULL);
1357 		}
1358 		(void) close(pdata);
1359 		pdata = s;
1360 #ifdef IP_TOS
1361 		tos = IPTOS_THROUGHPUT;
1362 		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1363 		    sizeof(int));
1364 #endif
1365 		reply(150, "Opening %s mode data connection for '%s'%s.",
1366 		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1367 		return (fdopen(pdata, mode));
1368 	}
1369 	if (data >= 0) {
1370 		reply(125, "Using existing data connection for '%s'%s.",
1371 		    name, sizebuf);
1372 		usedefault = 1;
1373 		return (fdopen(data, mode));
1374 	}
1375 	if (usedefault)
1376 		data_dest = his_addr;
1377 	usedefault = 1;
1378 	file = getdatasock(mode);
1379 	if (file == NULL) {
1380 		reply(425, "Can't create data socket (%s,%d): %s.",
1381 		    inet_ntoa(data_source.sin_addr),
1382 		    ntohs(data_source.sin_port), strerror(errno));
1383 		return (NULL);
1384 	}
1385 	data = fileno(file);
1386 	while (connect(data, (struct sockaddr *)&data_dest,
1387 	    sizeof(data_dest)) < 0) {
1388 		if (errno == EADDRINUSE && retry < swaitmax) {
1389 			sleep((unsigned) swaitint);
1390 			retry += swaitint;
1391 			continue;
1392 		}
1393 		perror_reply(425, "Can't build data connection");
1394 		(void) fclose(file);
1395 		data = -1;
1396 		return (NULL);
1397 	}
1398 	reply(150, "Opening %s mode data connection for '%s'%s.",
1399 	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1400 	return (file);
1401 }
1402 
1403 /*
1404  * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1405  * encapsulation of the data subject to Mode, Structure, and Type.
1406  *
1407  * NB: Form isn't handled.
1408  */
1409 static void
1410 send_data(instr, outstr, blksize, filesize, isreg)
1411 	FILE *instr, *outstr;
1412 	off_t blksize;
1413 	off_t filesize;
1414 	int isreg;
1415 {
1416 	int c, cnt, filefd, netfd;
1417 	char *buf, *bp;
1418 	size_t len;
1419 
1420 	transflag++;
1421 	if (setjmp(urgcatch)) {
1422 		transflag = 0;
1423 		return;
1424 	}
1425 	switch (type) {
1426 
1427 	case TYPE_A:
1428 		while ((c = getc(instr)) != EOF) {
1429 			byte_count++;
1430 			if (c == '\n') {
1431 				if (ferror(outstr))
1432 					goto data_err;
1433 				(void) putc('\r', outstr);
1434 			}
1435 			(void) putc(c, outstr);
1436 		}
1437 		fflush(outstr);
1438 		transflag = 0;
1439 		if (ferror(instr))
1440 			goto file_err;
1441 		if (ferror(outstr))
1442 			goto data_err;
1443 		reply(226, "Transfer complete.");
1444 		return;
1445 
1446 	case TYPE_I:
1447 	case TYPE_L:
1448 		/*
1449 		 * isreg is only set if we are not doing restart and we
1450 		 * are sending a regular file
1451 		 */
1452 		netfd = fileno(outstr);
1453 		filefd = fileno(instr);
1454 
1455 		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1456 			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1457 				   (off_t)0);
1458 			if (buf == MAP_FAILED) {
1459 				syslog(LOG_WARNING, "mmap(%lu): %m",
1460 				       (unsigned long)filesize);
1461 				goto oldway;
1462 			}
1463 			bp = buf;
1464 			len = filesize;
1465 			do {
1466 				cnt = write(netfd, bp, len);
1467 				len -= cnt;
1468 				bp += cnt;
1469 				if (cnt > 0) byte_count += cnt;
1470 			} while(cnt > 0 && len > 0);
1471 
1472 			transflag = 0;
1473 			munmap(buf, (size_t)filesize);
1474 			if (cnt < 0)
1475 				goto data_err;
1476 			reply(226, "Transfer complete.");
1477 			return;
1478 		}
1479 
1480 oldway:
1481 		if ((buf = malloc((u_int)blksize)) == NULL) {
1482 			transflag = 0;
1483 			perror_reply(451, "Local resource failure: malloc");
1484 			return;
1485 		}
1486 
1487 		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1488 		    write(netfd, buf, cnt) == cnt)
1489 			byte_count += cnt;
1490 		transflag = 0;
1491 		(void)free(buf);
1492 		if (cnt != 0) {
1493 			if (cnt < 0)
1494 				goto file_err;
1495 			goto data_err;
1496 		}
1497 		reply(226, "Transfer complete.");
1498 		return;
1499 	default:
1500 		transflag = 0;
1501 		reply(550, "Unimplemented TYPE %d in send_data", type);
1502 		return;
1503 	}
1504 
1505 data_err:
1506 	transflag = 0;
1507 	perror_reply(426, "Data connection");
1508 	return;
1509 
1510 file_err:
1511 	transflag = 0;
1512 	perror_reply(551, "Error on input file");
1513 }
1514 
1515 /*
1516  * Transfer data from peer to "outstr" using the appropriate encapulation of
1517  * the data subject to Mode, Structure, and Type.
1518  *
1519  * N.B.: Form isn't handled.
1520  */
1521 static int
1522 receive_data(instr, outstr)
1523 	FILE *instr, *outstr;
1524 {
1525 	int c;
1526 	int cnt, bare_lfs;
1527 	char buf[BUFSIZ];
1528 
1529 	transflag++;
1530 	if (setjmp(urgcatch)) {
1531 		transflag = 0;
1532 		return (-1);
1533 	}
1534 
1535 	bare_lfs = 0;
1536 
1537 	switch (type) {
1538 
1539 	case TYPE_I:
1540 	case TYPE_L:
1541 		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1542 			if (write(fileno(outstr), buf, cnt) != cnt)
1543 				goto file_err;
1544 			byte_count += cnt;
1545 		}
1546 		if (cnt < 0)
1547 			goto data_err;
1548 		transflag = 0;
1549 		return (0);
1550 
1551 	case TYPE_E:
1552 		reply(553, "TYPE E not implemented.");
1553 		transflag = 0;
1554 		return (-1);
1555 
1556 	case TYPE_A:
1557 		while ((c = getc(instr)) != EOF) {
1558 			byte_count++;
1559 			if (c == '\n')
1560 				bare_lfs++;
1561 			while (c == '\r') {
1562 				if (ferror(outstr))
1563 					goto data_err;
1564 				if ((c = getc(instr)) != '\n') {
1565 					(void) putc ('\r', outstr);
1566 					if (c == '\0' || c == EOF)
1567 						goto contin2;
1568 				}
1569 			}
1570 			(void) putc(c, outstr);
1571 	contin2:	;
1572 		}
1573 		fflush(outstr);
1574 		if (ferror(instr))
1575 			goto data_err;
1576 		if (ferror(outstr))
1577 			goto file_err;
1578 		transflag = 0;
1579 		if (bare_lfs) {
1580 			lreply(226,
1581 		"WARNING! %d bare linefeeds received in ASCII mode",
1582 			    bare_lfs);
1583 		(void)printf("   File may not have transferred correctly.\r\n");
1584 		}
1585 		return (0);
1586 	default:
1587 		reply(550, "Unimplemented TYPE %d in receive_data", type);
1588 		transflag = 0;
1589 		return (-1);
1590 	}
1591 
1592 data_err:
1593 	transflag = 0;
1594 	perror_reply(426, "Data Connection");
1595 	return (-1);
1596 
1597 file_err:
1598 	transflag = 0;
1599 	perror_reply(452, "Error writing file");
1600 	return (-1);
1601 }
1602 
1603 void
1604 statfilecmd(filename)
1605 	char *filename;
1606 {
1607 	FILE *fin;
1608 	int c;
1609 	char line[LINE_MAX];
1610 
1611 	(void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename);
1612 	fin = ftpd_popen(line, "r");
1613 	lreply(211, "status of %s:", filename);
1614 	while ((c = getc(fin)) != EOF) {
1615 		if (c == '\n') {
1616 			if (ferror(stdout)){
1617 				perror_reply(421, "control connection");
1618 				(void) ftpd_pclose(fin);
1619 				dologout(1);
1620 				/* NOTREACHED */
1621 			}
1622 			if (ferror(fin)) {
1623 				perror_reply(551, filename);
1624 				(void) ftpd_pclose(fin);
1625 				return;
1626 			}
1627 			(void) putc('\r', stdout);
1628 		}
1629 		(void) putc(c, stdout);
1630 	}
1631 	(void) ftpd_pclose(fin);
1632 	reply(211, "End of Status");
1633 }
1634 
1635 void
1636 statcmd()
1637 {
1638 	struct sockaddr_in *sin;
1639 	u_char *a, *p;
1640 
1641 	lreply(211, "%s FTP server status:", hostname, version);
1642 	printf("     %s\r\n", version);
1643 	printf("     Connected to %s", remotehost);
1644 	if (!isdigit(remotehost[0]))
1645 		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1646 	printf("\r\n");
1647 	if (logged_in) {
1648 		if (guest)
1649 			printf("     Logged in anonymously\r\n");
1650 		else
1651 			printf("     Logged in as %s\r\n", pw->pw_name);
1652 	} else if (askpasswd)
1653 		printf("     Waiting for password\r\n");
1654 	else
1655 		printf("     Waiting for user name\r\n");
1656 	printf("     TYPE: %s", typenames[type]);
1657 	if (type == TYPE_A || type == TYPE_E)
1658 		printf(", FORM: %s", formnames[form]);
1659 	if (type == TYPE_L)
1660 #if NBBY == 8
1661 		printf(" %d", NBBY);
1662 #else
1663 		printf(" %d", bytesize);	/* need definition! */
1664 #endif
1665 	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1666 	    strunames[stru], modenames[mode]);
1667 	if (data != -1)
1668 		printf("     Data connection open\r\n");
1669 	else if (pdata != -1) {
1670 		printf("     in Passive mode");
1671 		sin = &pasv_addr;
1672 		goto printaddr;
1673 	} else if (usedefault == 0) {
1674 		printf("     PORT");
1675 		sin = &data_dest;
1676 printaddr:
1677 		a = (u_char *) &sin->sin_addr;
1678 		p = (u_char *) &sin->sin_port;
1679 #define UC(b) (((int) b) & 0xff)
1680 		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1681 			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1682 #undef UC
1683 	} else
1684 		printf("     No data connection\r\n");
1685 	reply(211, "End of status");
1686 }
1687 
1688 void
1689 fatal(s)
1690 	char *s;
1691 {
1692 
1693 	reply(451, "Error in server: %s\n", s);
1694 	reply(221, "Closing connection due to server error.");
1695 	dologout(0);
1696 	/* NOTREACHED */
1697 }
1698 
1699 void
1700 #if __STDC__
1701 reply(int n, const char *fmt, ...)
1702 #else
1703 reply(n, fmt, va_alist)
1704 	int n;
1705 	char *fmt;
1706         va_dcl
1707 #endif
1708 {
1709 	va_list ap;
1710 #if __STDC__
1711 	va_start(ap, fmt);
1712 #else
1713 	va_start(ap);
1714 #endif
1715 	(void)printf("%d ", n);
1716 	(void)vprintf(fmt, ap);
1717 	(void)printf("\r\n");
1718 	(void)fflush(stdout);
1719 	if (debug) {
1720 		syslog(LOG_DEBUG, "<--- %d ", n);
1721 		vsyslog(LOG_DEBUG, fmt, ap);
1722 	}
1723 }
1724 
1725 void
1726 #if __STDC__
1727 lreply(int n, const char *fmt, ...)
1728 #else
1729 lreply(n, fmt, va_alist)
1730 	int n;
1731 	char *fmt;
1732         va_dcl
1733 #endif
1734 {
1735 	va_list ap;
1736 #if __STDC__
1737 	va_start(ap, fmt);
1738 #else
1739 	va_start(ap);
1740 #endif
1741 	(void)printf("%d- ", n);
1742 	(void)vprintf(fmt, ap);
1743 	(void)printf("\r\n");
1744 	(void)fflush(stdout);
1745 	if (debug) {
1746 		syslog(LOG_DEBUG, "<--- %d- ", n);
1747 		vsyslog(LOG_DEBUG, fmt, ap);
1748 	}
1749 }
1750 
1751 static void
1752 ack(s)
1753 	char *s;
1754 {
1755 
1756 	reply(250, "%s command successful.", s);
1757 }
1758 
1759 void
1760 nack(s)
1761 	char *s;
1762 {
1763 
1764 	reply(502, "%s command not implemented.", s);
1765 }
1766 
1767 /* ARGSUSED */
1768 void
1769 yyerror(s)
1770 	char *s;
1771 {
1772 	char *cp;
1773 
1774 	if ((cp = strchr(cbuf,'\n')))
1775 		*cp = '\0';
1776 	reply(500, "'%s': command not understood.", cbuf);
1777 }
1778 
1779 void
1780 delete(name)
1781 	char *name;
1782 {
1783 	struct stat st;
1784 
1785 	LOGCMD("delete", name);
1786 	if (stat(name, &st) < 0) {
1787 		perror_reply(550, name);
1788 		return;
1789 	}
1790 	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1791 		if (rmdir(name) < 0) {
1792 			perror_reply(550, name);
1793 			return;
1794 		}
1795 		goto done;
1796 	}
1797 	if (unlink(name) < 0) {
1798 		perror_reply(550, name);
1799 		return;
1800 	}
1801 done:
1802 	ack("DELE");
1803 }
1804 
1805 void
1806 cwd(path)
1807 	char *path;
1808 {
1809 
1810 	if (chdir(path) < 0)
1811 		perror_reply(550, path);
1812 	else
1813 		ack("CWD");
1814 }
1815 
1816 void
1817 makedir(name)
1818 	char *name;
1819 {
1820 
1821 	LOGCMD("mkdir", name);
1822 	if (mkdir(name, 0777) < 0)
1823 		perror_reply(550, name);
1824 	else
1825 		reply(257, "MKD command successful.");
1826 }
1827 
1828 void
1829 removedir(name)
1830 	char *name;
1831 {
1832 
1833 	LOGCMD("rmdir", name);
1834 	if (rmdir(name) < 0)
1835 		perror_reply(550, name);
1836 	else
1837 		ack("RMD");
1838 }
1839 
1840 void
1841 pwd()
1842 {
1843 	char path[MAXPATHLEN + 1];
1844 
1845 	if (getwd(path) == (char *)NULL)
1846 		reply(550, "%s.", path);
1847 	else
1848 		reply(257, "\"%s\" is current directory.", path);
1849 }
1850 
1851 char *
1852 renamefrom(name)
1853 	char *name;
1854 {
1855 	struct stat st;
1856 
1857 	if (stat(name, &st) < 0) {
1858 		perror_reply(550, name);
1859 		return ((char *)0);
1860 	}
1861 	reply(350, "File exists, ready for destination name");
1862 	return (name);
1863 }
1864 
1865 void
1866 renamecmd(from, to)
1867 	char *from, *to;
1868 {
1869 	struct stat st;
1870 
1871 	LOGCMD2("rename", from, to);
1872 
1873 	if (guest && (stat(to, &st) == 0)) {
1874 		reply(550, "%s: permission denied", to);
1875 		return;
1876 	}
1877 
1878 	if (rename(from, to) < 0)
1879 		perror_reply(550, "rename");
1880 	else
1881 		ack("RNTO");
1882 }
1883 
1884 static void
1885 dolog(sin)
1886 	struct sockaddr_in *sin;
1887 {
1888 	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1889 		sizeof(struct in_addr), AF_INET);
1890 
1891 	if (hp)
1892 		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
1893 	else
1894 		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1895 		    sizeof(remotehost));
1896 #ifdef SETPROCTITLE
1897 #ifdef VIRTUAL_HOSTING
1898 	if (thishost != firsthost)
1899 		snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)",
1900 			 remotehost, hostname);
1901 	else
1902 #endif
1903 		snprintf(proctitle, sizeof(proctitle), "%s: connected",
1904 			 remotehost);
1905 	setproctitle("%s", proctitle);
1906 #endif /* SETPROCTITLE */
1907 
1908 	if (logging) {
1909 #ifdef VIRTUAL_HOSTING
1910 		if (thishost != firsthost)
1911 			syslog(LOG_INFO, "connection from %s (to %s)",
1912 			       remotehost, hostname);
1913 		else
1914 #endif
1915 			syslog(LOG_INFO, "connection from %s", remotehost);
1916 	}
1917 }
1918 
1919 /*
1920  * Record logout in wtmp file
1921  * and exit with supplied status.
1922  */
1923 void
1924 dologout(status)
1925 	int status;
1926 {
1927 	/*
1928 	 * Prevent reception of SIGURG from resulting in a resumption
1929 	 * back to the main program loop.
1930 	 */
1931 	transflag = 0;
1932 
1933 	if (logged_in) {
1934 		(void) seteuid((uid_t)0);
1935 		ftpd_logwtmp(ttyline, "", "");
1936 #if defined(KERBEROS)
1937 		if (!notickets && krbtkfile_env)
1938 			unlink(krbtkfile_env);
1939 #endif
1940 	}
1941 	/* beware of flushing buffers after a SIGPIPE */
1942 	_exit(status);
1943 }
1944 
1945 static void
1946 myoob(signo)
1947 	int signo;
1948 {
1949 	char *cp;
1950 
1951 	/* only process if transfer occurring */
1952 	if (!transflag)
1953 		return;
1954 	cp = tmpline;
1955 	if (getline(cp, 7, stdin) == NULL) {
1956 		reply(221, "You could at least say goodbye.");
1957 		dologout(0);
1958 	}
1959 	upper(cp);
1960 	if (strcmp(cp, "ABOR\r\n") == 0) {
1961 		tmpline[0] = '\0';
1962 		reply(426, "Transfer aborted. Data connection closed.");
1963 		reply(226, "Abort successful");
1964 		longjmp(urgcatch, 1);
1965 	}
1966 	if (strcmp(cp, "STAT\r\n") == 0) {
1967 		if (file_size != (off_t) -1)
1968 			reply(213, "Status: %qd of %qd bytes transferred",
1969 			    byte_count, file_size);
1970 		else
1971 			reply(213, "Status: %qd bytes transferred", byte_count);
1972 	}
1973 }
1974 
1975 /*
1976  * Note: a response of 425 is not mentioned as a possible response to
1977  *	the PASV command in RFC959. However, it has been blessed as
1978  *	a legitimate response by Jon Postel in a telephone conversation
1979  *	with Rick Adams on 25 Jan 89.
1980  */
1981 void
1982 passive()
1983 {
1984 	int len;
1985 	char *p, *a;
1986 
1987 	if (pdata >= 0)		/* close old port if one set */
1988 		close(pdata);
1989 
1990 	pdata = socket(AF_INET, SOCK_STREAM, 0);
1991 	if (pdata < 0) {
1992 		perror_reply(425, "Can't open passive connection");
1993 		return;
1994 	}
1995 
1996 	(void) seteuid((uid_t)0);
1997 
1998 #ifdef IP_PORTRANGE
1999 	{
2000 	    int on = restricted_data_ports ? IP_PORTRANGE_HIGH
2001 					   : IP_PORTRANGE_DEFAULT;
2002 
2003 	    if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2004 			    (char *)&on, sizeof(on)) < 0)
2005 		    goto pasv_error;
2006 	}
2007 #endif
2008 
2009 	pasv_addr = ctrl_addr;
2010 	pasv_addr.sin_port = 0;
2011 	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2012 		 sizeof(pasv_addr)) < 0)
2013 		goto pasv_error;
2014 
2015 	(void) seteuid((uid_t)pw->pw_uid);
2016 
2017 	len = sizeof(pasv_addr);
2018 	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2019 		goto pasv_error;
2020 	if (listen(pdata, 1) < 0)
2021 		goto pasv_error;
2022 	a = (char *) &pasv_addr.sin_addr;
2023 	p = (char *) &pasv_addr.sin_port;
2024 
2025 #define UC(b) (((int) b) & 0xff)
2026 
2027 	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2028 		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2029 	return;
2030 
2031 pasv_error:
2032 	(void) seteuid((uid_t)pw->pw_uid);
2033 	(void) close(pdata);
2034 	pdata = -1;
2035 	perror_reply(425, "Can't open passive connection");
2036 	return;
2037 }
2038 
2039 /*
2040  * Generate unique name for file with basename "local".
2041  * The file named "local" is already known to exist.
2042  * Generates failure reply on error.
2043  */
2044 static char *
2045 gunique(local)
2046 	char *local;
2047 {
2048 	static char new[MAXPATHLEN];
2049 	struct stat st;
2050 	int count;
2051 	char *cp;
2052 
2053 	cp = strrchr(local, '/');
2054 	if (cp)
2055 		*cp = '\0';
2056 	if (stat(cp ? local : ".", &st) < 0) {
2057 		perror_reply(553, cp ? local : ".");
2058 		return ((char *) 0);
2059 	}
2060 	if (cp)
2061 		*cp = '/';
2062 	(void) snprintf(new, sizeof(new), "%s", local);
2063 	cp = new + strlen(new);
2064 	*cp++ = '.';
2065 	for (count = 1; count < 100; count++) {
2066 		(void)sprintf(cp, "%d", count);
2067 		if (stat(new, &st) < 0)
2068 			return (new);
2069 	}
2070 	reply(452, "Unique file name cannot be created.");
2071 	return (NULL);
2072 }
2073 
2074 /*
2075  * Format and send reply containing system error number.
2076  */
2077 void
2078 perror_reply(code, string)
2079 	int code;
2080 	char *string;
2081 {
2082 
2083 	reply(code, "%s: %s.", string, strerror(errno));
2084 }
2085 
2086 static char *onefile[] = {
2087 	"",
2088 	0
2089 };
2090 
2091 void
2092 send_file_list(whichf)
2093 	char *whichf;
2094 {
2095 	struct stat st;
2096 	DIR *dirp = NULL;
2097 	struct dirent *dir;
2098 	FILE *dout = NULL;
2099 	char **dirlist, *dirname;
2100 	int simple = 0;
2101 	int freeglob = 0;
2102 	glob_t gl;
2103 
2104 	if (strpbrk(whichf, "~{[*?") != NULL) {
2105 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
2106 
2107 		memset(&gl, 0, sizeof(gl));
2108 		freeglob = 1;
2109 		if (glob(whichf, flags, 0, &gl)) {
2110 			reply(550, "not found");
2111 			goto out;
2112 		} else if (gl.gl_pathc == 0) {
2113 			errno = ENOENT;
2114 			perror_reply(550, whichf);
2115 			goto out;
2116 		}
2117 		dirlist = gl.gl_pathv;
2118 	} else {
2119 		onefile[0] = whichf;
2120 		dirlist = onefile;
2121 		simple = 1;
2122 	}
2123 
2124 	if (setjmp(urgcatch)) {
2125 		transflag = 0;
2126 		goto out;
2127 	}
2128 	while ((dirname = *dirlist++)) {
2129 		if (stat(dirname, &st) < 0) {
2130 			/*
2131 			 * If user typed "ls -l", etc, and the client
2132 			 * used NLST, do what the user meant.
2133 			 */
2134 			if (dirname[0] == '-' && *dirlist == NULL &&
2135 			    transflag == 0) {
2136 				retrieve(_PATH_LS " %s", dirname);
2137 				goto out;
2138 			}
2139 			perror_reply(550, whichf);
2140 			if (dout != NULL) {
2141 				(void) fclose(dout);
2142 				transflag = 0;
2143 				data = -1;
2144 				pdata = -1;
2145 			}
2146 			goto out;
2147 		}
2148 
2149 		if (S_ISREG(st.st_mode)) {
2150 			if (dout == NULL) {
2151 				dout = dataconn("file list", (off_t)-1, "w");
2152 				if (dout == NULL)
2153 					goto out;
2154 				transflag++;
2155 			}
2156 			fprintf(dout, "%s%s\n", dirname,
2157 				type == TYPE_A ? "\r" : "");
2158 			byte_count += strlen(dirname) + 1;
2159 			continue;
2160 		} else if (!S_ISDIR(st.st_mode))
2161 			continue;
2162 
2163 		if ((dirp = opendir(dirname)) == NULL)
2164 			continue;
2165 
2166 		while ((dir = readdir(dirp)) != NULL) {
2167 			char nbuf[MAXPATHLEN];
2168 
2169 			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2170 				continue;
2171 			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2172 			    dir->d_namlen == 2)
2173 				continue;
2174 
2175 			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
2176 
2177 			/*
2178 			 * We have to do a stat to insure it's
2179 			 * not a directory or special file.
2180 			 */
2181 			if (simple || (stat(nbuf, &st) == 0 &&
2182 			    S_ISREG(st.st_mode))) {
2183 				if (dout == NULL) {
2184 					dout = dataconn("file list", (off_t)-1,
2185 						"w");
2186 					if (dout == NULL)
2187 						goto out;
2188 					transflag++;
2189 				}
2190 				if (nbuf[0] == '.' && nbuf[1] == '/')
2191 					fprintf(dout, "%s%s\n", &nbuf[2],
2192 						type == TYPE_A ? "\r" : "");
2193 				else
2194 					fprintf(dout, "%s%s\n", nbuf,
2195 						type == TYPE_A ? "\r" : "");
2196 				byte_count += strlen(nbuf) + 1;
2197 			}
2198 		}
2199 		(void) closedir(dirp);
2200 	}
2201 
2202 	if (dout == NULL)
2203 		reply(550, "No files found.");
2204 	else if (ferror(dout) != 0)
2205 		perror_reply(550, "Data connection");
2206 	else
2207 		reply(226, "Transfer complete.");
2208 
2209 	transflag = 0;
2210 	if (dout != NULL)
2211 		(void) fclose(dout);
2212 	data = -1;
2213 	pdata = -1;
2214 out:
2215 	if (freeglob) {
2216 		freeglob = 0;
2217 		globfree(&gl);
2218 	}
2219 }
2220 
2221 void
2222 reapchild(signo)
2223 	int signo;
2224 {
2225 	while (wait3(NULL, WNOHANG, NULL) > 0);
2226 }
2227 
2228 #ifdef OLD_SETPROCTITLE
2229 /*
2230  * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
2231  * Warning, since this is usually started from inetd.conf, it often doesn't
2232  * have much of an environment or arglist to overwrite.
2233  */
2234 void
2235 #if __STDC__
2236 setproctitle(const char *fmt, ...)
2237 #else
2238 setproctitle(fmt, va_alist)
2239 	char *fmt;
2240         va_dcl
2241 #endif
2242 {
2243 	int i;
2244 	va_list ap;
2245 	char *p, *bp, ch;
2246 	char buf[LINE_MAX];
2247 
2248 #if __STDC__
2249 	va_start(ap, fmt);
2250 #else
2251 	va_start(ap);
2252 #endif
2253 	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
2254 
2255 	/* make ps print our process name */
2256 	p = Argv[0];
2257 	*p++ = '-';
2258 
2259 	i = strlen(buf);
2260 	if (i > LastArgv - p - 2) {
2261 		i = LastArgv - p - 2;
2262 		buf[i] = '\0';
2263 	}
2264 	bp = buf;
2265 	while (ch = *bp++)
2266 		if (ch != '\n' && ch != '\r')
2267 			*p++ = ch;
2268 	while (p < LastArgv)
2269 		*p++ = ' ';
2270 }
2271 #endif /* OLD_SETPROCTITLE */
2272 
2273 static void
2274 logxfer(name, size, start)
2275 	char *name;
2276 	long size;
2277 	long start;
2278 {
2279 	char buf[1024];
2280 	char path[MAXPATHLEN + 1];
2281 	long now;
2282 
2283 	if (statfd >= 0 && getwd(path) != NULL) {
2284 		time(&now);
2285 		snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n",
2286 			ctime(&now)+4, ident, remotehost,
2287 			path, name, size, now - start + (now == start));
2288 		write(statfd, buf, strlen(buf));
2289 	}
2290 }
2291