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