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