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