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