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