ftpd.c revision 1.169
1/*	$OpenBSD: ftpd.c,v 1.169 2005/12/01 17:36:59 pvalchev Exp $	*/
2/*	$NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $	*/
3
4/*
5 * Copyright (C) 1997 and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
35 *	The Regents of the University of California.  All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 *    may be used to endorse or promote products derived from this software
47 *    without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 */
61
62#ifndef lint
63static const char copyright[] =
64"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
65	The Regents of the University of California.  All rights reserved.\n";
66#endif /* not lint */
67
68#ifndef lint
69#if 0
70static const char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
71#else
72static const char rcsid[] =
73    "$OpenBSD: ftpd.c,v 1.169 2005/12/01 17:36:59 pvalchev Exp $";
74#endif
75#endif /* not lint */
76
77/*
78 * FTP server.
79 */
80#include <sys/param.h>
81#include <sys/stat.h>
82#include <sys/ioctl.h>
83#include <sys/socket.h>
84#include <sys/wait.h>
85#include <sys/mman.h>
86
87#include <netinet/in.h>
88#include <netinet/in_systm.h>
89#include <netinet/ip.h>
90#include <netinet/tcp.h>
91
92#define	FTP_NAMES
93#include <arpa/ftp.h>
94#include <arpa/inet.h>
95#include <arpa/telnet.h>
96
97#include <bsd_auth.h>
98#include <ctype.h>
99#include <dirent.h>
100#include <errno.h>
101#include <fcntl.h>
102#include <glob.h>
103#include <limits.h>
104#include <login_cap.h>
105#include <netdb.h>
106#include <pwd.h>
107#include <signal.h>
108#include <stdarg.h>
109#include <stdio.h>
110#include <stdlib.h>
111#include <string.h>
112#include <syslog.h>
113#include <time.h>
114#include <vis.h>
115#include <unistd.h>
116#include <util.h>
117#include <utmp.h>
118#include <poll.h>
119
120#if defined(TCPWRAPPERS)
121#include <tcpd.h>
122#endif	/* TCPWRAPPERS */
123
124#include "pathnames.h"
125#include "extern.h"
126#include "monitor.h"
127
128static char version[] = "Version 6.6/OpenBSD";
129
130extern	off_t restart_point;
131extern	char cbuf[];
132
133union sockunion server_addr;
134union sockunion ctrl_addr;
135union sockunion data_source;
136union sockunion data_dest;
137union sockunion his_addr;
138union sockunion pasv_addr;
139
140sigset_t allsigs;
141
142int	daemon_mode = 0;
143int	data;
144int	logged_in;
145struct	passwd *pw;
146int	debug = 0;
147int	timeout = 900;    /* timeout after 15 minutes of inactivity */
148int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
149int	logging;
150int	anon_ok = 1;
151int	anon_only = 0;
152int	multihome = 0;
153int	guest;
154int	stats;
155int	statfd = -1;
156int	portcheck = 1;
157int	dochroot;
158int	type;
159int	form;
160int	stru;			/* avoid C keyword */
161int	mode;
162int	doutmp = 0;		/* update utmp file */
163int	usedefault = 1;		/* for data transfers */
164int	pdata = -1;		/* for passive mode */
165int	family = AF_UNSPEC;
166volatile sig_atomic_t transflag;
167off_t	file_size;
168off_t	byte_count;
169#if !defined(CMASK) || CMASK == 0
170#undef CMASK
171#define CMASK 022
172#endif
173int	defumask = CMASK;		/* default umask value */
174int	umaskchange = 1;		/* allow user to change umask value. */
175char	tmpline[7];
176char	hostname[MAXHOSTNAMELEN];
177char	remotehost[MAXHOSTNAMELEN];
178char	dhostname[MAXHOSTNAMELEN];
179char	*guestpw;
180char	ttyline[20];
181char	*tty = ttyline;		/* for klogin */
182static struct utmp utmp;	/* for utmp */
183static	login_cap_t *lc;
184static	auth_session_t *as;
185static	volatile sig_atomic_t recvurg;
186
187#if defined(TCPWRAPPERS)
188int	allow_severity = LOG_INFO;
189int	deny_severity = LOG_NOTICE;
190#endif	/* TCPWRAPPERS */
191
192char	*ident = NULL;
193
194
195int epsvall = 0;
196
197/*
198 * Timeout intervals for retrying connections
199 * to hosts that don't accept PORT cmds.  This
200 * is a kludge, but given the problems with TCP...
201 */
202#define	SWAITMAX	90	/* wait at most 90 seconds */
203#define	SWAITINT	5	/* interval between retries */
204
205int	swaitmax = SWAITMAX;
206int	swaitint = SWAITINT;
207
208#ifdef HASSETPROCTITLE
209char	proctitle[BUFSIZ];	/* initial part of title */
210#endif /* HASSETPROCTITLE */
211
212#define LOGCMD(cmd, file) \
213	if (logging > 1) \
214	    syslog(LOG_INFO,"%s %s%s", cmd, \
215		*(file) == '/' ? "" : curdir(), file);
216#define LOGCMD2(cmd, file1, file2) \
217	 if (logging > 1) \
218	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
219		*(file1) == '/' ? "" : curdir(), file1, \
220		*(file2) == '/' ? "" : curdir(), file2);
221#define LOGBYTES(cmd, file, cnt) \
222	if (logging > 1) { \
223		if (cnt == (off_t)-1) \
224		    syslog(LOG_INFO,"%s %s%s", cmd, \
225			*(file) == '/' ? "" : curdir(), file); \
226		else \
227		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
228			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
229	}
230
231static void	 ack(char *);
232static void	 sigurg(int);
233static void	 myoob(void);
234static int	 checkuser(char *, char *);
235static FILE	*dataconn(char *, off_t, char *);
236static void	 dolog(struct sockaddr *);
237static char	*copy_dir(char *, struct passwd *);
238static char	*curdir(void);
239static void	 end_login(void);
240static FILE	*getdatasock(char *);
241static int	 guniquefd(char *, char **);
242static void	 lostconn(int);
243static void	 sigquit(int);
244static int	 receive_data(FILE *, FILE *);
245static void	 replydirname(const char *, const char *);
246static int	 send_data(FILE *, FILE *, off_t, off_t, int);
247static struct passwd *
248		 sgetpwnam(char *, struct passwd *);
249static void	 reapchild(int);
250#if defined(TCPWRAPPERS)
251static int	 check_host(struct sockaddr *);
252#endif /* TCPWRAPPERS */
253static void	 usage(void);
254
255void	 logxfer(char *, off_t, time_t);
256void	 set_slave_signals(void);
257
258static char *
259curdir(void)
260{
261	static char path[MAXPATHLEN+1];	/* path + '/' */
262
263	if (getcwd(path, sizeof(path)-1) == NULL)
264		return ("");
265	if (path[1] != '\0')		/* special case for root dir. */
266		strlcat(path, "/", sizeof path);
267	/* For guest account, skip / since it's chrooted */
268	return (guest ? path+1 : path);
269}
270
271char *argstr = "AdDhnlMSt:T:u:UvP46";
272
273static void
274usage(void)
275{
276	syslog(LOG_ERR,
277	    "usage: ftpd [-46ADdlMnPSU] [-T maxtimeout] [-t timeout] [-u mask]");
278	exit(2);
279}
280
281int
282main(int argc, char *argv[])
283{
284	socklen_t addrlen;
285	int ch, on = 1, tos;
286	char *cp, line[LINE_MAX];
287	FILE *fp;
288	struct hostent *hp;
289	struct sigaction sa;
290	int error = 0;
291
292	tzset();		/* in case no timezone database in ~ftp */
293	sigfillset(&allsigs);	/* used to block signals while root */
294	sigemptyset(&sa.sa_mask);
295	sa.sa_flags = SA_RESTART;
296
297	while ((ch = getopt(argc, argv, argstr)) != -1) {
298		switch (ch) {
299		case 'A':
300			anon_only = 1;
301			break;
302
303		case 'd':
304		case 'v':		/* deprecated */
305			debug = 1;
306			break;
307
308		case 'D':
309			daemon_mode = 1;
310			break;
311
312		case 'P':
313			portcheck = 0;
314			break;
315
316		case 'h':		/* deprecated */
317			break;
318
319		case 'l':
320			logging++;	/* > 1 == extra logging */
321			break;
322
323		case 'M':
324			multihome = 1;
325			break;
326
327		case 'n':
328			anon_ok = 0;
329			break;
330
331		case 'S':
332			stats = 1;
333			break;
334
335		case 't':
336			timeout = atoi(optarg);
337			if (maxtimeout < timeout)
338				maxtimeout = timeout;
339			break;
340
341		case 'T':
342			maxtimeout = atoi(optarg);
343			if (timeout > maxtimeout)
344				timeout = maxtimeout;
345			break;
346
347		case 'u':
348		    {
349			long val = 0;
350			char *p;
351			umaskchange = 0;
352
353			val = strtol(optarg, &p, 8);
354			if (*p != '\0' || val < 0 || (val & ~ACCESSPERMS)) {
355				syslog(LOG_ERR,
356				    "%s is a bad value for -u, aborting..",
357				    optarg);
358				exit(2);
359			} else
360				defumask = val;
361			break;
362		    }
363
364		case 'U':
365			doutmp = 1;
366			break;
367
368		case '4':
369			family = AF_INET;
370			break;
371
372		case '6':
373			family = AF_INET6;
374			break;
375
376		default:
377			usage();
378			break;
379		}
380	}
381
382	(void) freopen(_PATH_DEVNULL, "w", stderr);
383
384	/*
385	 * LOG_NDELAY sets up the logging connection immediately,
386	 * necessary for anonymous ftp's that chroot and can't do it later.
387	 */
388	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
389
390	if (getpwnam(FTPD_PRIVSEP_USER) == NULL) {
391		syslog(LOG_ERR, "privilege separation user %s not found",
392		    FTPD_PRIVSEP_USER);
393		exit(1);
394	}
395	endpwent();
396
397	if (daemon_mode) {
398		int *fds, n, i, fd;
399		struct pollfd *pfds;
400		struct addrinfo hints, *res, *res0;
401
402		/*
403		 * Detach from parent.
404		 */
405		if (daemon(1, 1) < 0) {
406			syslog(LOG_ERR, "failed to become a daemon");
407			exit(1);
408		}
409		sa.sa_handler = reapchild;
410		(void) sigaction(SIGCHLD, &sa, NULL);
411
412		memset(&hints, 0, sizeof(hints));
413		hints.ai_family = family;
414		hints.ai_socktype = SOCK_STREAM;
415		hints.ai_protocol = IPPROTO_TCP;
416		hints.ai_flags = AI_PASSIVE;
417		error = getaddrinfo(NULL, "ftp", &hints, &res0);
418		if (error) {
419			syslog(LOG_ERR, "%s", gai_strerror(error));
420			exit(1);
421		}
422
423		n = 0;
424		for (res = res0; res; res = res->ai_next)
425			n++;
426
427		fds = malloc(n * sizeof(int));
428		pfds = malloc(n * sizeof(struct pollfd));
429		if (!fds || !pfds) {
430			syslog(LOG_ERR, "%s", strerror(errno));
431			exit(1);
432		}
433
434		/*
435		 * Open sockets, bind it to the FTP port, and start
436		 * listening.
437		 */
438		n = 0;
439		for (res = res0; res; res = res->ai_next) {
440			fds[n] = socket(res->ai_family, res->ai_socktype,
441			    res->ai_protocol);
442			if (fds[n] < 0)
443				continue;
444
445			if (setsockopt(fds[n], SOL_SOCKET, SO_REUSEADDR,
446			    (char *)&on, sizeof(on)) < 0) {
447				close(fds[n]);
448				fds[n] = -1;
449				continue;
450			}
451
452			if (bind(fds[n], res->ai_addr, res->ai_addrlen) < 0) {
453				close(fds[n]);
454				fds[n] = -1;
455				continue;
456			}
457			if (listen(fds[n], 32) < 0) {
458				close(fds[n]);
459				fds[n] = -1;
460				continue;
461			}
462
463			pfds[n].fd = fds[n];
464			pfds[n].events = POLLIN;
465			n++;
466		}
467		freeaddrinfo(res0);
468
469		if (n == 0) {
470			syslog(LOG_ERR, "could not open control socket");
471			exit(1);
472		}
473
474		/* Stash pid in pidfile */
475		if (pidfile(NULL))
476			syslog(LOG_ERR, "can't open pidfile: %m");
477		/*
478		 * Loop forever accepting connection requests and forking off
479		 * children to handle them.
480		 */
481		while (1) {
482			if (poll(pfds, n, INFTIM) < 0) {
483				if (errno == EINTR)
484					continue;
485				syslog(LOG_ERR, "poll: %m");
486				exit(1);
487			}
488			for (i = 0; i < n; i++)
489				if (pfds[i].revents & POLLIN) {
490					addrlen = sizeof(his_addr);
491					fd = accept(pfds[i].fd,
492					    (struct sockaddr *)&his_addr,
493					    &addrlen);
494					if (fd != -1) {
495						if (fork() == 0)
496							goto child;
497						close(fd);
498					}
499				}
500		}
501
502	child:
503		/* child */
504		(void)dup2(fd, STDIN_FILENO);
505		(void)dup2(fd, STDOUT_FILENO);
506		for (i = 0; i < n; i++)
507			close(fds[i]);
508#if defined(TCPWRAPPERS)
509		/* ..in the child. */
510		if (!check_host((struct sockaddr *)&his_addr))
511			exit(1);
512#endif	/* TCPWRAPPERS */
513	} else {
514		addrlen = sizeof(his_addr);
515		if (getpeername(0, (struct sockaddr *)&his_addr,
516				&addrlen) < 0) {
517			/* syslog(LOG_ERR, "getpeername (%s): %m", argv[0]); */
518			exit(1);
519		}
520	}
521
522	/* set this here so klogin can use it... */
523	(void)snprintf(ttyline, sizeof(ttyline), "ftp%ld", (long)getpid());
524
525	set_slave_signals();
526
527	addrlen = sizeof(ctrl_addr);
528	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
529		syslog(LOG_ERR, "getsockname: %m");
530		exit(1);
531	}
532	if (his_addr.su_family == AF_INET6
533	 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
534#if 1
535		/*
536		 * IPv4 control connection arrived to AF_INET6 socket.
537		 * I hate to do this, but this is the easiest solution.
538		 */
539		union sockunion tmp_addr;
540		const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
541
542		tmp_addr = his_addr;
543		memset(&his_addr, 0, sizeof(his_addr));
544		his_addr.su_sin.sin_family = AF_INET;
545		his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
546		memcpy(&his_addr.su_sin.sin_addr,
547		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
548		    sizeof(his_addr.su_sin.sin_addr));
549		his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
550
551		tmp_addr = ctrl_addr;
552		memset(&ctrl_addr, 0, sizeof(ctrl_addr));
553		ctrl_addr.su_sin.sin_family = AF_INET;
554		ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
555		memcpy(&ctrl_addr.su_sin.sin_addr,
556		    &tmp_addr.su_sin6.sin6_addr.s6_addr[off],
557		    sizeof(ctrl_addr.su_sin.sin_addr));
558		ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
559#else
560		while (fgets(line, sizeof(line), fd) != NULL) {
561			if ((cp = strchr(line, '\n')) != NULL)
562				*cp = '\0';
563			lreply(530, "%s", line);
564		}
565		(void) fflush(stdout);
566		(void) fclose(fd);
567		reply(530,
568			"Connection from IPv4 mapped address is not supported.");
569		exit(0);
570#endif
571	}
572#ifdef IP_TOS
573	if (his_addr.su_family == AF_INET) {
574		tos = IPTOS_LOWDELAY;
575		if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
576		    sizeof(int)) < 0)
577			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
578	}
579#endif
580	data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
581
582	/* Try to handle urgent data inline */
583#ifdef SO_OOBINLINE
584	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
585		syslog(LOG_ERR, "setsockopt: %m");
586#endif
587
588	dolog((struct sockaddr *)&his_addr);
589	/*
590	 * Set up default state
591	 */
592	data = -1;
593	type = TYPE_A;
594	form = FORM_N;
595	stru = STRU_F;
596	mode = MODE_S;
597	tmpline[0] = '\0';
598
599	/* If logins are disabled, print out the message. */
600	if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
601		while (fgets(line, sizeof(line), fp) != NULL) {
602			if ((cp = strchr(line, '\n')) != NULL)
603				*cp = '\0';
604			lreply(530, "%s", line);
605		}
606		(void) fflush(stdout);
607		(void) fclose(fp);
608		reply(530, "System not available.");
609		exit(0);
610	}
611	if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
612		while (fgets(line, sizeof(line), fp) != NULL) {
613			if ((cp = strchr(line, '\n')) != NULL)
614				*cp = '\0';
615			lreply(220, "%s", line);
616		}
617		(void) fflush(stdout);
618		(void) fclose(fp);
619		/* reply(220,) must follow */
620	}
621	(void) gethostname(hostname, sizeof(hostname));
622
623	/* Make sure hostname is fully qualified. */
624	hp = gethostbyname(hostname);
625	if (hp != NULL)
626		strlcpy(hostname, hp->h_name, sizeof(hostname));
627
628	if (multihome) {
629		error = getnameinfo((struct sockaddr *)&ctrl_addr,
630		    ctrl_addr.su_len, dhostname, sizeof(dhostname), NULL, 0, 0);
631	}
632
633	if (error != 0)
634		reply(220, "FTP server (%s) ready.", version);
635	else
636		reply(220, "%s FTP server (%s) ready.",
637		    (multihome ? dhostname : hostname), version);
638
639	monitor_init();
640
641	for (;;)
642		(void) yyparse();
643	/* NOTREACHED */
644}
645
646/*
647 * Signal handlers.
648 */
649
650static void
651lostconn(int signo)
652{
653	struct syslog_data sdata = SYSLOG_DATA_INIT;
654
655	if (debug)
656		syslog_r(LOG_DEBUG, &sdata, "lost connection");
657	dologout(1);
658}
659
660static void
661sigquit(int signo)
662{
663	struct syslog_data sdata = SYSLOG_DATA_INIT;
664
665	syslog_r(LOG_ERR, &sdata, "got signal %s", sys_signame[signo]);
666	dologout(1);
667}
668
669/*
670 * Save the result of a getpwnam.  Used for USER command, since
671 * the data returned must not be clobbered by any other command
672 * (e.g., globbing).
673 */
674static struct passwd *
675sgetpwnam(char *name, struct passwd *pw)
676{
677	static struct passwd *save;
678	struct passwd *old;
679
680	if (pw == NULL && (pw = getpwnam(name)) == NULL)
681		return (NULL);
682	old = save;
683	save = pw_dup(pw);
684	if (save == NULL) {
685		perror_reply(421, "Local resource failure: malloc");
686		dologout(1);
687		/* NOTREACHED */
688	}
689	if (old) {
690		memset(old->pw_passwd, 0, strlen(old->pw_passwd));
691		free(old);
692	}
693	return (save);
694}
695
696static int login_attempts;	/* number of failed login attempts */
697static int askpasswd;		/* had user command, ask for passwd */
698static char curname[MAXLOGNAME];	/* current USER name */
699
700/*
701 * USER command.
702 * Sets global passwd pointer pw if named account exists and is acceptable;
703 * sets askpasswd if a PASS command is expected.  If logged in previously,
704 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
705 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
706 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
707 * requesting login privileges.  Disallow anyone who does not have a standard
708 * shell as returned by getusershell().  Disallow anyone mentioned in the file
709 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
710 */
711void
712user(char *name)
713{
714	char *cp, *shell, *style, *host;
715	char *class = NULL;
716
717	if (logged_in) {
718		kill_slave();
719		end_login();
720	}
721
722	/* Close session from previous user if there was one. */
723	if (as) {
724		auth_close(as);
725		as = NULL;
726	}
727	if (lc) {
728		login_close(lc);
729		lc = NULL;
730	}
731
732	if ((style = strchr(name, ':')) != NULL)
733		*style++ = 0;
734
735	guest = 0;
736	host = multihome ? dhostname : hostname;
737	if (anon_ok &&
738	    (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0)) {
739		if (checkuser(_PATH_FTPUSERS, "ftp") ||
740		    checkuser(_PATH_FTPUSERS, "anonymous"))
741			reply(530, "User %s access denied.", name);
742		else if ((pw = sgetpwnam("ftp", NULL)) != NULL) {
743			guest = 1;
744			askpasswd = 1;
745			lc = login_getclass(pw->pw_class);
746			if ((as = auth_open()) == NULL ||
747			    auth_setpwd(as, pw) != 0 ||
748			    auth_setoption(as, "FTPD_HOST", host) < 0) {
749				if (as) {
750					auth_close(as);
751					as = NULL;
752				}
753				login_close(lc);
754				lc = NULL;
755				reply(421, "Local resource failure");
756				return;
757			}
758			reply(331,
759			"Guest login ok, send your email address as password.");
760		} else
761			reply(530, "User %s unknown.", name);
762		if (!askpasswd && logging)
763			syslog(LOG_NOTICE,
764			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
765		return;
766	}
767
768	shell = _PATH_BSHELL;
769	if ((pw = sgetpwnam(name, NULL))) {
770		class = pw->pw_class;
771		if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
772			shell = pw->pw_shell;
773		while ((cp = getusershell()) != NULL)
774			if (strcmp(cp, shell) == 0)
775				break;
776		shell = cp;
777		endusershell();
778	}
779
780	/* Get login class; if invalid style treat like unknown user. */
781	lc = login_getclass(class);
782	if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
783		login_close(lc);
784		lc = NULL;
785		pw = NULL;
786	}
787
788	/* Do pre-authentication setup. */
789	if (lc && ((as = auth_open()) == NULL ||
790	    (pw != NULL && auth_setpwd(as, pw) != 0) ||
791	    auth_setitem(as, AUTHV_STYLE, style) < 0 ||
792	    auth_setitem(as, AUTHV_NAME, name) < 0 ||
793	    auth_setitem(as, AUTHV_CLASS, class) < 0 ||
794	    auth_setoption(as, "login", "yes") < 0 ||
795	    auth_setoption(as, "notickets", "yes") < 0 ||
796	    auth_setoption(as, "FTPD_HOST", host) < 0)) {
797		if (as) {
798			auth_close(as);
799			as = NULL;
800		}
801		login_close(lc);
802		lc = NULL;
803		reply(421, "Local resource failure");
804		return;
805	}
806	if (logging)
807		strlcpy(curname, name, sizeof(curname));
808
809	dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
810	    checkuser(_PATH_FTPCHROOT, name);
811	if (anon_only && !dochroot) {
812		if (anon_ok)
813			reply(530, "Sorry, only anonymous ftp allowed.");
814		else
815			reply(530, "User %s access denied.", name);
816		return;
817	}
818	if (pw) {
819		if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
820			reply(530, "User %s access denied.", name);
821			if (logging)
822				syslog(LOG_NOTICE,
823				    "FTP LOGIN REFUSED FROM %s, %s",
824				    remotehost, name);
825			pw = NULL;
826			return;
827		}
828	}
829
830	if (as != NULL && (cp = auth_challenge(as)) != NULL)
831		reply(331, "%s", cp);
832	else
833		reply(331, "Password required for %s.", name);
834
835	askpasswd = 1;
836	/*
837	 * Delay before reading passwd after first failed
838	 * attempt to slow down passwd-guessing programs.
839	 */
840	if (login_attempts)
841		sleep((unsigned) login_attempts);
842}
843
844/*
845 * Check if a user is in the file "fname"
846 */
847static int
848checkuser(char *fname, char *name)
849{
850	FILE *fp;
851	int found = 0;
852	char *p, line[BUFSIZ];
853
854	if ((fp = fopen(fname, "r")) != NULL) {
855		while (fgets(line, sizeof(line), fp) != NULL)
856			if ((p = strchr(line, '\n')) != NULL) {
857				*p = '\0';
858				if (line[0] == '#')
859					continue;
860				if (strcmp(line, name) == 0) {
861					found = 1;
862					break;
863				}
864			}
865		(void) fclose(fp);
866	}
867	return (found);
868}
869
870/*
871 * Terminate login as previous user, if any, resetting state;
872 * used when USER command is given or login fails.
873 */
874static void
875end_login(void)
876{
877	sigprocmask (SIG_BLOCK, &allsigs, NULL);
878	if (logged_in) {
879		ftpdlogwtmp(ttyline, "", "");
880		if (doutmp)
881			ftpd_logout(utmp.ut_line);
882	}
883	reply(530, "Please reconnect to work as another user");
884	_exit(0);
885}
886
887enum auth_ret
888pass(char *passwd)
889{
890	int authok, flags;
891	FILE *fp;
892	static char homedir[MAXPATHLEN];
893	char *motd, *dir, rootdir[MAXPATHLEN];
894	size_t sz_pw_dir;
895
896	if (logged_in || askpasswd == 0) {
897		reply(503, "Login with USER first.");
898		return (AUTH_FAILED);
899	}
900	askpasswd = 0;
901	if (!guest) {		/* "ftp" is only account allowed no password */
902		authok = 0;
903		if (pw == NULL || pw->pw_passwd[0] == '\0') {
904			useconds_t us;
905
906			/* Sleep between 1 and 3 seconds to emulate a crypt. */
907			us = arc4random() % 3000000;
908			usleep(us);
909			if (as != NULL) {
910				auth_close(as);
911				as = NULL;
912			}
913		} else {
914			authok = auth_userresponse(as, passwd, 0);
915			as = NULL;
916		}
917		if (authok == 0) {
918			reply(530, "Login incorrect.");
919			if (logging)
920				syslog(LOG_NOTICE,
921				    "FTP LOGIN FAILED FROM %s, %s",
922				    remotehost, curname);
923			pw = NULL;
924			if (login_attempts++ >= 5) {
925				syslog(LOG_NOTICE,
926				    "repeated login failures from %s",
927				    remotehost);
928				kill_slave();
929				_exit(0);
930			}
931			return (AUTH_FAILED);
932		}
933	} else if (lc != NULL) {
934		/* Save anonymous' password. */
935		if (guestpw != NULL)
936			free(guestpw);
937		guestpw = strdup(passwd);
938		if (guestpw == NULL) {
939			kill_slave();
940			fatal("Out of memory.");
941		}
942
943		authok = auth_approval(as, lc, pw->pw_name, "ftp");
944		auth_close(as);
945		as = NULL;
946		if (authok == 0) {
947			syslog(LOG_INFO|LOG_AUTH,
948			    "FTP LOGIN FAILED (HOST) as %s: approval failure.",
949			    pw->pw_name);
950			reply(530, "Approval failure.");
951			kill_slave();
952			_exit(0);
953		}
954	} else {
955		syslog(LOG_INFO|LOG_AUTH,
956		    "FTP LOGIN CLASS %s MISSING for %s: approval failure.",
957		    pw->pw_class, pw->pw_name);
958		reply(530, "Permission denied.");
959		kill_slave();
960		_exit(0);
961	}
962
963	if (monitor_post_auth() == 1) {
964		/* Post-auth monitor process */
965		logged_in = 1;
966		return (AUTH_MONITOR);
967	}
968
969	login_attempts = 0;		/* this time successful */
970	/* set umask via setusercontext() unless -u flag was given. */
971	flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
972	if (umaskchange)
973		flags |= LOGIN_SETUMASK;
974	else
975		(void) umask(defumask);
976	if (setusercontext(lc, pw, (uid_t)0, flags) != 0) {
977		perror_reply(451, "Local resource failure: setusercontext");
978		syslog(LOG_NOTICE, "setusercontext: %m");
979		dologout(1);
980		/* NOTREACHED */
981	}
982
983	/* open wtmp before chroot */
984	ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
985
986	/* open utmp before chroot */
987	if (doutmp) {
988		memset((void *)&utmp, 0, sizeof(utmp));
989		(void)time(&utmp.ut_time);
990		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
991		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
992		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
993		ftpd_login(&utmp);
994	}
995
996	/* open stats file before chroot */
997	if (guest && (stats == 1) && (statfd < 0))
998		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
999			stats = 0;
1000
1001	logged_in = 1;
1002
1003	if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
1004		char *newdir;
1005
1006		newdir = copy_dir(dir, pw);
1007		if (newdir == NULL) {
1008			perror_reply(421, "Local resource failure: malloc");
1009			dologout(1);
1010			/* NOTREACHED */
1011		}
1012		pw->pw_dir = newdir;
1013		pw = sgetpwnam(NULL, pw);
1014		free(dir);
1015		free(newdir);
1016	}
1017
1018	/* make sure pw->pw_dir is big enough to hold "/" */
1019	sz_pw_dir = strlen(pw->pw_dir) + 1;
1020	if (sz_pw_dir < 2) {
1021		pw->pw_dir = "/";
1022		pw = sgetpwnam(NULL, pw);
1023		sz_pw_dir = 2;
1024	}
1025
1026	if (guest || dochroot) {
1027		if (multihome && guest) {
1028			struct stat ts;
1029
1030			/* Compute root directory. */
1031			snprintf(rootdir, sizeof(rootdir), "%s/%s",
1032			    pw->pw_dir, dhostname);
1033			if (stat(rootdir, &ts) < 0) {
1034				snprintf(rootdir, sizeof(rootdir), "%s/%s",
1035				    pw->pw_dir, hostname);
1036			}
1037		} else
1038			strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
1039	}
1040	if (guest) {
1041		/*
1042		 * We MUST do a chdir() after the chroot. Otherwise
1043		 * the old current directory will be accessible as "."
1044		 * outside the new root!
1045		 */
1046		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1047			reply(550, "Can't set guest privileges.");
1048			goto bad;
1049		}
1050		strlcpy(pw->pw_dir, "/", sz_pw_dir);
1051		if (setenv("HOME", "/", 1) == -1) {
1052			reply(550, "Can't setup environment.");
1053			goto bad;
1054		}
1055	} else if (dochroot) {
1056		if (chroot(rootdir) < 0 || chdir("/") < 0) {
1057			reply(550, "Can't change root.");
1058			goto bad;
1059		}
1060		strlcpy(pw->pw_dir, "/", sz_pw_dir);
1061		if (setenv("HOME", "/", 1) == -1) {
1062			reply(550, "Can't setup environment.");
1063			goto bad;
1064		}
1065	} else if (chdir(pw->pw_dir) < 0) {
1066		if (chdir("/") < 0) {
1067			reply(530, "User %s: can't change directory to %s.",
1068			    pw->pw_name, pw->pw_dir);
1069			goto bad;
1070		} else
1071			lreply(230, "No directory! Logging in with home=/");
1072	}
1073	if (setegid(pw->pw_gid) < 0 || setgid(pw->pw_gid) < 0) {
1074		reply(550, "Can't set gid.");
1075		goto bad;
1076	}
1077	if (seteuid(pw->pw_uid) < 0 || setuid(pw->pw_uid) < 0) {
1078		reply(550, "Can't set uid.");
1079		goto bad;
1080	}
1081	sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
1082
1083	/*
1084	 * Set home directory so that use of ~ (tilde) works correctly.
1085	 */
1086	if (getcwd(homedir, MAXPATHLEN) != NULL) {
1087		if (setenv("HOME", homedir, 1) == -1) {
1088			reply(550, "Can't setup environment.");
1089			goto bad;
1090		}
1091	}
1092
1093	/*
1094	 * Display a login message, if it exists.
1095	 * N.B. reply(230,) must follow the message.
1096	 */
1097	motd = login_getcapstr(lc, "welcome", NULL, NULL);
1098	if ((fp = fopen(motd ? motd : _PATH_FTPLOGINMESG, "r")) != NULL) {
1099		char *cp, line[LINE_MAX];
1100
1101		while (fgets(line, sizeof(line), fp) != NULL) {
1102			if ((cp = strchr(line, '\n')) != NULL)
1103				*cp = '\0';
1104			lreply(230, "%s", line);
1105		}
1106		(void) fflush(stdout);
1107		(void) fclose(fp);
1108	}
1109	if (motd != NULL)
1110		free(motd);
1111	if (guest) {
1112		if (ident != NULL)
1113			free(ident);
1114		ident = strdup(passwd);
1115		if (ident == NULL)
1116			fatal("Ran out of memory.");
1117		reply(230, "Guest login ok, access restrictions apply.");
1118#ifdef HASSETPROCTITLE
1119		snprintf(proctitle, sizeof(proctitle),
1120		    "%s: anonymous/%.*s", remotehost,
1121		    (int)(sizeof(proctitle) - sizeof(remotehost) -
1122		    sizeof(": anonymous/")), passwd);
1123		setproctitle("%s", proctitle);
1124#endif /* HASSETPROCTITLE */
1125		if (logging)
1126			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
1127			    remotehost, passwd);
1128	} else {
1129		reply(230, "User %s logged in.", pw->pw_name);
1130#ifdef HASSETPROCTITLE
1131		snprintf(proctitle, sizeof(proctitle),
1132		    "%s: %s", remotehost, pw->pw_name);
1133		setproctitle("%s", proctitle);
1134#endif /* HASSETPROCTITLE */
1135		if (logging)
1136			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
1137			    remotehost, pw->pw_name);
1138	}
1139	login_close(lc);
1140	lc = NULL;
1141	return (AUTH_SLAVE);
1142bad:
1143	/* Forget all about it... */
1144	login_close(lc);
1145	lc = NULL;
1146	end_login();
1147	return (AUTH_FAILED);
1148}
1149
1150void
1151retrieve(char *cmd, char *name)
1152{
1153	FILE *fin, *dout;
1154	struct stat st;
1155	int (*closefunc)(FILE *);
1156	time_t start;
1157
1158	if (cmd == 0) {
1159		fin = fopen(name, "r"), closefunc = fclose;
1160		st.st_size = 0;
1161	} else {
1162		char line[BUFSIZ];
1163
1164		(void) snprintf(line, sizeof(line), cmd, name);
1165		name = line;
1166		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
1167		st.st_size = -1;
1168		st.st_blksize = BUFSIZ;
1169	}
1170	if (fin == NULL) {
1171		if (errno != 0) {
1172			perror_reply(550, name);
1173			if (cmd == 0) {
1174				LOGCMD("get", name);
1175			}
1176		}
1177		return;
1178	}
1179	byte_count = -1;
1180	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
1181		reply(550, "%s: not a plain file.", name);
1182		goto done;
1183	}
1184	if (restart_point) {
1185		if (type == TYPE_A) {
1186			off_t i, n;
1187			int c;
1188
1189			n = restart_point;
1190			i = 0;
1191			while (i++ < n) {
1192				if ((c = getc(fin)) == EOF) {
1193					if (ferror(fin)) {
1194						perror_reply(550, name);
1195						goto done;
1196					} else
1197						break;
1198				}
1199				if (c == '\n')
1200					i++;
1201			}
1202		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1203			perror_reply(550, name);
1204			goto done;
1205		}
1206	}
1207	dout = dataconn(name, st.st_size, "w");
1208	if (dout == NULL)
1209		goto done;
1210	time(&start);
1211	send_data(fin, dout, st.st_blksize, st.st_size,
1212	    (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));
1213	if ((cmd == 0) && stats)
1214		logxfer(name, byte_count, start);
1215	(void) fclose(dout);
1216	data = -1;
1217done:
1218	if (pdata >= 0)
1219		(void) close(pdata);
1220	pdata = -1;
1221	if (cmd == 0)
1222		LOGBYTES("get", name, byte_count);
1223	(*closefunc)(fin);
1224}
1225
1226void
1227store(char *name, char *mode, int unique)
1228{
1229	FILE *fout, *din;
1230	int (*closefunc)(FILE *);
1231	struct stat st;
1232	int fd;
1233
1234	if (restart_point && *mode != 'a')
1235		mode = "r+";
1236
1237	if (unique && stat(name, &st) == 0) {
1238		char *nam;
1239
1240		fd = guniquefd(name, &nam);
1241		if (fd == -1) {
1242			LOGCMD(*mode == 'w' ? "put" : "append", name);
1243			return;
1244		}
1245		name = nam;
1246		fout = fdopen(fd, mode);
1247	} else
1248		fout = fopen(name, mode);
1249
1250	closefunc = fclose;
1251	if (fout == NULL) {
1252		perror_reply(553, name);
1253		LOGCMD(*mode == 'w' ? "put" : "append", name);
1254		return;
1255	}
1256	byte_count = -1;
1257	if (restart_point) {
1258		if (type == TYPE_A) {
1259			off_t i, n;
1260			int c;
1261
1262			n = restart_point;
1263			i = 0;
1264			while (i++ < n) {
1265				if ((c = getc(fout)) == EOF) {
1266					if (ferror(fout)) {
1267						perror_reply(550, name);
1268						goto done;
1269					} else
1270						break;
1271				}
1272				if (c == '\n')
1273					i++;
1274			}
1275			/*
1276			 * We must do this seek to "current" position
1277			 * because we are changing from reading to
1278			 * writing.
1279			 */
1280			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1281				perror_reply(550, name);
1282				goto done;
1283			}
1284		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1285			perror_reply(550, name);
1286			goto done;
1287		}
1288	}
1289	din = dataconn(name, (off_t)-1, "r");
1290	if (din == NULL)
1291		goto done;
1292	if (receive_data(din, fout) == 0) {
1293		if (unique)
1294			reply(226, "Transfer complete (unique file name:%s).",
1295			    name);
1296		else
1297			reply(226, "Transfer complete.");
1298	}
1299	(void) fclose(din);
1300	data = -1;
1301	pdata = -1;
1302done:
1303	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1304	(*closefunc)(fout);
1305}
1306
1307static FILE *
1308getdatasock(char *mode)
1309{
1310	int on = 1, s, t, tries;
1311
1312	if (data >= 0)
1313		return (fdopen(data, mode));
1314	sigprocmask (SIG_BLOCK, &allsigs, NULL);
1315	s = monitor_socket(ctrl_addr.su_family);
1316	if (s < 0)
1317		goto bad;
1318	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1319	    (char *) &on, sizeof(on)) < 0)
1320		goto bad;
1321	/* anchor socket to avoid multi-homing problems */
1322	data_source = ctrl_addr;
1323	data_source.su_port = htons(20); /* ftp-data port */
1324	for (tries = 1; ; tries++) {
1325		if (monitor_bind(s, (struct sockaddr *)&data_source,
1326		    data_source.su_len) >= 0)
1327			break;
1328		if (errno != EADDRINUSE || tries > 10)
1329			goto bad;
1330		sleep(tries);
1331	}
1332	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1333
1334#ifdef IP_TOS
1335	if (ctrl_addr.su_family == AF_INET) {
1336		on = IPTOS_THROUGHPUT;
1337		if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1338		    sizeof(int)) < 0)
1339			syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1340	}
1341#endif
1342#ifdef TCP_NOPUSH
1343	/*
1344	 * Turn off push flag to keep sender TCP from sending short packets
1345	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
1346	 * to set the send buffer size as well, but that may not be desirable
1347	 * in heavy-load situations.
1348	 */
1349	on = 1;
1350	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof(on)) < 0)
1351		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
1352#endif
1353#ifdef SO_SNDBUF
1354	on = 65536;
1355	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof(on)) < 0)
1356		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
1357#endif
1358
1359	return (fdopen(s, mode));
1360bad:
1361	/* Return the real value of errno (close may change it) */
1362	t = errno;
1363	sigprocmask (SIG_UNBLOCK, &allsigs, NULL);
1364	if (s >= 0)
1365		(void) close(s);
1366	errno = t;
1367	return (NULL);
1368}
1369
1370static FILE *
1371dataconn(char *name, off_t size, char *mode)
1372{
1373	char sizebuf[32];
1374	FILE *file;
1375	int retry = 0;
1376	in_port_t *p;
1377	u_char *fa, *ha;
1378	int alen;
1379	int error;
1380
1381	file_size = size;
1382	byte_count = 0;
1383	if (size != (off_t) -1) {
1384		(void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
1385				size);
1386	} else
1387		sizebuf[0] = '\0';
1388	if (pdata >= 0) {
1389		union sockunion from;
1390		int s;
1391		socklen_t fromlen = sizeof(from);
1392
1393		(void) alarm ((unsigned) timeout);
1394		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1395		(void) alarm (0);
1396		if (s < 0) {
1397			reply(425, "Can't open data connection.");
1398			(void) close(pdata);
1399			pdata = -1;
1400			return (NULL);
1401		}
1402		switch (from.su_family) {
1403		case AF_INET:
1404			p = (in_port_t *)&from.su_sin.sin_port;
1405			fa = (u_char *)&from.su_sin.sin_addr;
1406			ha = (u_char *)&his_addr.su_sin.sin_addr;
1407			alen = sizeof(struct in_addr);
1408			break;
1409		case AF_INET6:
1410			p = (in_port_t *)&from.su_sin6.sin6_port;
1411			fa = (u_char *)&from.su_sin6.sin6_addr;
1412			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1413			alen = sizeof(struct in6_addr);
1414			break;
1415		default:
1416			perror_reply(425, "Can't build data connection");
1417			(void) close(pdata);
1418			(void) close(s);
1419			pdata = -1;
1420			return (NULL);
1421		}
1422		if (from.su_family != his_addr.su_family ||
1423		    ntohs(*p) < IPPORT_RESERVED) {
1424			perror_reply(425, "Can't build data connection");
1425			(void) close(pdata);
1426			(void) close(s);
1427			pdata = -1;
1428			return (NULL);
1429		}
1430		if (portcheck && memcmp(fa, ha, alen) != 0) {
1431			perror_reply(435, "Can't build data connection");
1432			(void) close(pdata);
1433			(void) close(s);
1434			pdata = -1;
1435			return (NULL);
1436		}
1437		(void) close(pdata);
1438		pdata = s;
1439		reply(150, "Opening %s mode data connection for '%s'%s.",
1440		    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1441		return (fdopen(pdata, mode));
1442	}
1443	if (data >= 0) {
1444		reply(125, "Using existing data connection for '%s'%s.",
1445		    name, sizebuf);
1446		usedefault = 1;
1447		return (fdopen(data, mode));
1448	}
1449	if (usedefault)
1450		data_dest = his_addr;
1451	usedefault = 1;
1452	do {
1453		file = getdatasock(mode);
1454		if (file == NULL) {
1455			char hbuf[MAXHOSTNAMELEN], pbuf[10];
1456
1457			error = getnameinfo((struct sockaddr *)&data_source,
1458			    data_source.su_len, hbuf, sizeof(hbuf), pbuf,
1459			    sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1460			if (error != 0)
1461				reply(425, "Can't create data socket: %s.",
1462				    strerror(errno));
1463			else
1464				reply(425,
1465				    "Can't create data socket (%s,%s): %s.",
1466				    hbuf, pbuf, strerror(errno));
1467			return (NULL);
1468		}
1469
1470		/*
1471		 * attempt to connect to reserved port on client machine;
1472		 * this looks like an attack
1473		 */
1474		switch (data_dest.su_family) {
1475		case AF_INET:
1476			p = (in_port_t *)&data_dest.su_sin.sin_port;
1477			fa = (u_char *)&data_dest.su_sin.sin_addr;
1478			ha = (u_char *)&his_addr.su_sin.sin_addr;
1479			alen = sizeof(struct in_addr);
1480			break;
1481		case AF_INET6:
1482			p = (in_port_t *)&data_dest.su_sin6.sin6_port;
1483			fa = (u_char *)&data_dest.su_sin6.sin6_addr;
1484			ha = (u_char *)&his_addr.su_sin6.sin6_addr;
1485			alen = sizeof(struct in6_addr);
1486			break;
1487		default:
1488			perror_reply(425, "Can't build data connection");
1489			(void) fclose(file);
1490			pdata = -1;
1491			return (NULL);
1492		}
1493		if (data_dest.su_family != his_addr.su_family ||
1494		    ntohs(*p) < IPPORT_RESERVED || ntohs(*p) == 2049) { /* XXX */
1495			perror_reply(425, "Can't build data connection");
1496			(void) fclose(file);
1497			return NULL;
1498		}
1499		if (portcheck && memcmp(fa, ha, alen) != 0) {
1500			perror_reply(435, "Can't build data connection");
1501			(void) fclose(file);
1502			return NULL;
1503		}
1504
1505		if (connect(fileno(file), (struct sockaddr *)&data_dest,
1506		    data_dest.su_len) == 0) {
1507			reply(150, "Opening %s mode data connection for '%s'%s.",
1508			    type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1509			data = fileno(file);
1510			return (file);
1511		}
1512		if (errno != EADDRINUSE)
1513			break;
1514		(void) fclose(file);
1515		sleep((unsigned) swaitint);
1516		retry += swaitint;
1517	} while (retry <= swaitmax);
1518	perror_reply(425, "Can't build data connection");
1519	(void) fclose(file);
1520	return (NULL);
1521}
1522
1523/*
1524 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1525 * encapsulation of the data subject to Mode, Structure, and Type.
1526 *
1527 * NB: Form isn't handled.
1528 */
1529static int
1530send_data(FILE *instr, FILE *outstr, off_t blksize, off_t filesize, int isreg)
1531{
1532	int c, cnt, filefd, netfd;
1533	char *buf, *bp;
1534	size_t len;
1535
1536	transflag++;
1537	switch (type) {
1538
1539	case TYPE_A:
1540		while ((c = getc(instr)) != EOF) {
1541			if (recvurg)
1542				goto got_oob;
1543			byte_count++;
1544			if (c == '\n') {
1545				if (ferror(outstr))
1546					goto data_err;
1547				(void) putc('\r', outstr);
1548			}
1549			(void) putc(c, outstr);
1550		}
1551		fflush(outstr);
1552		transflag = 0;
1553		if (ferror(instr))
1554			goto file_err;
1555		if (ferror(outstr))
1556			goto data_err;
1557		reply(226, "Transfer complete.");
1558		return(0);
1559
1560	case TYPE_I:
1561	case TYPE_L:
1562		/*
1563		 * isreg is only set if we are not doing restart and we
1564		 * are sending a regular file
1565		 */
1566		netfd = fileno(outstr);
1567		filefd = fileno(instr);
1568
1569		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1570			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1571			    (off_t)0);
1572			if (buf == MAP_FAILED) {
1573				syslog(LOG_WARNING, "mmap(%lu): %m",
1574				    (unsigned long)filesize);
1575				goto oldway;
1576			}
1577			bp = buf;
1578			len = filesize;
1579			do {
1580				cnt = write(netfd, bp, len);
1581				if (recvurg) {
1582					munmap(buf, (size_t)filesize);
1583					goto got_oob;
1584				}
1585				len -= cnt;
1586				bp += cnt;
1587				if (cnt > 0)
1588					byte_count += cnt;
1589			} while(cnt > 0 && len > 0);
1590
1591			transflag = 0;
1592			munmap(buf, (size_t)filesize);
1593			if (cnt < 0)
1594				goto data_err;
1595			reply(226, "Transfer complete.");
1596			return(0);
1597		}
1598
1599oldway:
1600		if ((buf = malloc((u_int)blksize)) == NULL) {
1601			transflag = 0;
1602			perror_reply(451, "Local resource failure: malloc");
1603			return(-1);
1604		}
1605
1606		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1607		    write(netfd, buf, cnt) == cnt)
1608			byte_count += cnt;
1609		transflag = 0;
1610		(void)free(buf);
1611		if (cnt != 0) {
1612			if (cnt < 0)
1613				goto file_err;
1614			goto data_err;
1615		}
1616		reply(226, "Transfer complete.");
1617		return(0);
1618	default:
1619		transflag = 0;
1620		reply(550, "Unimplemented TYPE %d in send_data", type);
1621		return(-1);
1622	}
1623
1624data_err:
1625	transflag = 0;
1626	perror_reply(426, "Data connection");
1627	return(-1);
1628
1629file_err:
1630	transflag = 0;
1631	perror_reply(551, "Error on input file");
1632	return(-1);
1633
1634got_oob:
1635	myoob();
1636	recvurg = 0;
1637	transflag = 0;
1638	return(-1);
1639}
1640
1641/*
1642 * Transfer data from peer to "outstr" using the appropriate encapulation of
1643 * the data subject to Mode, Structure, and Type.
1644 *
1645 * N.B.: Form isn't handled.
1646 */
1647static int
1648receive_data(FILE *instr, FILE *outstr)
1649{
1650	int c;
1651	int cnt;
1652	char buf[BUFSIZ];
1653	struct sigaction sa, sa_saved;
1654	volatile int bare_lfs = 0;
1655
1656	transflag++;
1657	switch (type) {
1658
1659	case TYPE_I:
1660	case TYPE_L:
1661		memset(&sa, 0, sizeof(sa));
1662		sigfillset(&sa.sa_mask);
1663		sa.sa_flags = SA_RESTART;
1664		sa.sa_handler = lostconn;
1665		(void) sigaction(SIGALRM, &sa, &sa_saved);
1666		do {
1667			(void) alarm ((unsigned) timeout);
1668			cnt = read(fileno(instr), buf, sizeof(buf));
1669			(void) alarm (0);
1670			if (recvurg)
1671				goto got_oob;
1672
1673			if (cnt > 0) {
1674				if (write(fileno(outstr), buf, cnt) != cnt)
1675					goto file_err;
1676				byte_count += cnt;
1677			}
1678		} while (cnt > 0);
1679		(void) sigaction(SIGALRM, &sa_saved, NULL);
1680		if (cnt < 0)
1681			goto data_err;
1682		transflag = 0;
1683		return (0);
1684
1685	case TYPE_E:
1686		reply(553, "TYPE E not implemented.");
1687		transflag = 0;
1688		return (-1);
1689
1690	case TYPE_A:
1691		while ((c = getc(instr)) != EOF) {
1692			if (recvurg)
1693				goto got_oob;
1694			byte_count++;
1695			if (c == '\n')
1696				bare_lfs++;
1697			while (c == '\r') {
1698				if (ferror(outstr))
1699					goto data_err;
1700				if ((c = getc(instr)) != '\n') {
1701					(void) putc ('\r', outstr);
1702					if (c == '\0' || c == EOF)
1703						goto contin2;
1704				}
1705			}
1706			(void) putc(c, outstr);
1707	contin2:	;
1708		}
1709		fflush(outstr);
1710		if (ferror(instr))
1711			goto data_err;
1712		if (ferror(outstr))
1713			goto file_err;
1714		transflag = 0;
1715		if (bare_lfs) {
1716			lreply(226,
1717			    "WARNING! %d bare linefeeds received in ASCII mode",
1718			    bare_lfs);
1719			printf("   File may not have transferred correctly.\r\n");
1720		}
1721		return (0);
1722	default:
1723		reply(550, "Unimplemented TYPE %d in receive_data", type);
1724		transflag = 0;
1725		return (-1);
1726	}
1727
1728data_err:
1729	transflag = 0;
1730	perror_reply(426, "Data Connection");
1731	return (-1);
1732
1733file_err:
1734	transflag = 0;
1735	perror_reply(452, "Error writing file");
1736	return (-1);
1737
1738got_oob:
1739	myoob();
1740	recvurg = 0;
1741	transflag = 0;
1742	return (-1);
1743}
1744
1745void
1746statfilecmd(char *filename)
1747{
1748	FILE *fin;
1749	int c;
1750	int atstart;
1751	char line[LINE_MAX];
1752
1753	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1754	fin = ftpd_popen(line, "r");
1755	lreply(211, "status of %s:", filename);
1756	atstart = 1;
1757	while ((c = getc(fin)) != EOF) {
1758		if (c == '\n') {
1759			if (ferror(stdout)){
1760				perror_reply(421, "control connection");
1761				(void) ftpd_pclose(fin);
1762				dologout(1);
1763				/* NOTREACHED */
1764			}
1765			if (ferror(fin)) {
1766				perror_reply(551, filename);
1767				(void) ftpd_pclose(fin);
1768				return;
1769			}
1770			(void) putc('\r', stdout);
1771		}
1772		if (atstart && isdigit(c))
1773			(void) putc(' ', stdout);
1774		(void) putc(c, stdout);
1775		atstart = (c == '\n');
1776	}
1777	(void) ftpd_pclose(fin);
1778	reply(211, "End of Status");
1779}
1780
1781void
1782statcmd(void)
1783{
1784	union sockunion *su;
1785	u_char *a, *p;
1786	char hbuf[MAXHOSTNAMELEN];
1787	int ispassive;
1788	int error;
1789
1790	lreply(211, "%s FTP server status:", hostname);
1791	printf("     %s\r\n", version);
1792	error = getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1793	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
1794	printf("     Connected to %s", remotehost);
1795	if (error == 0 && strcmp(remotehost, hbuf) != 0)
1796		printf(" (%s)", hbuf);
1797	printf("\r\n");
1798	if (logged_in) {
1799		if (guest)
1800			printf("     Logged in anonymously\r\n");
1801		else
1802			printf("     Logged in as %s\r\n", pw->pw_name);
1803	} else if (askpasswd)
1804		printf("     Waiting for password\r\n");
1805	else
1806		printf("     Waiting for user name\r\n");
1807	printf("     TYPE: %s", typenames[type]);
1808	if (type == TYPE_A || type == TYPE_E)
1809		printf(", FORM: %s", formnames[form]);
1810	if (type == TYPE_L)
1811#if NBBY == 8
1812		printf(" %d", NBBY);
1813#else
1814		printf(" %d", bytesize);	/* need definition! */
1815#endif
1816	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1817	    strunames[stru], modenames[mode]);
1818	ispassive = 0;
1819	if (data != -1)
1820		printf("     Data connection open\r\n");
1821	else if (pdata != -1) {
1822		printf("     in Passive mode\r\n");
1823		su = (union sockunion *)&pasv_addr;
1824		ispassive++;
1825		goto printaddr;
1826	} else if (usedefault == 0) {
1827		su = (union sockunion *)&data_dest;
1828printaddr:
1829		/* PASV/PORT */
1830		if (su->su_family == AF_INET) {
1831			if (ispassive)
1832				printf("211- PASV ");
1833			else
1834				printf("211- PORT ");
1835			a = (u_char *) &su->su_sin.sin_addr;
1836			p = (u_char *) &su->su_sin.sin_port;
1837			printf("(%u,%u,%u,%u,%u,%u)\r\n",
1838			    a[0], a[1], a[2], a[3],
1839			    p[0], p[1]);
1840		}
1841
1842		/* LPSV/LPRT */
1843	    {
1844		int alen, af, i;
1845
1846		alen = 0;
1847		switch (su->su_family) {
1848		case AF_INET:
1849			a = (u_char *) &su->su_sin.sin_addr;
1850			p = (u_char *) &su->su_sin.sin_port;
1851			alen = sizeof(su->su_sin.sin_addr);
1852			af = 4;
1853			break;
1854		case AF_INET6:
1855			a = (u_char *) &su->su_sin6.sin6_addr;
1856			p = (u_char *) &su->su_sin6.sin6_port;
1857			alen = sizeof(su->su_sin6.sin6_addr);
1858			af = 6;
1859			break;
1860		default:
1861			af = 0;
1862			break;
1863		}
1864		if (af) {
1865			if (ispassive)
1866				printf("211- LPSV ");
1867			else
1868				printf("211- LPRT ");
1869			printf("(%u,%u", af, alen);
1870			for (i = 0; i < alen; i++)
1871				printf(",%u", a[i]);
1872			printf(",%u,%u,%u)\r\n", 2, p[0], p[1]);
1873		}
1874	    }
1875
1876		/* EPRT/EPSV */
1877	    {
1878		u_char af;
1879
1880		switch (su->su_family) {
1881		case AF_INET:
1882			af = 1;
1883			break;
1884		case AF_INET6:
1885			af = 2;
1886			break;
1887		default:
1888			af = 0;
1889			break;
1890		}
1891		if (af) {
1892			char pbuf[10];
1893			union sockunion tmp = *su;
1894
1895			if (tmp.su_family == AF_INET6)
1896				tmp.su_sin6.sin6_scope_id = 0;
1897			if (getnameinfo((struct sockaddr *)&tmp, tmp.su_len,
1898			    hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1899			    NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
1900				if (ispassive)
1901					printf("211- EPSV ");
1902				else
1903					printf("211- EPRT ");
1904				printf("(|%u|%s|%s|)\r\n",
1905					af, hbuf, pbuf);
1906			}
1907		}
1908	    }
1909	} else
1910		printf("     No data connection\r\n");
1911	reply(211, "End of status");
1912}
1913
1914void
1915fatal(char *s)
1916{
1917
1918	reply(451, "Error in server: %s", s);
1919	reply(221, "Closing connection due to server error.");
1920	dologout(0);
1921	/* NOTREACHED */
1922}
1923
1924void
1925reply(int n, const char *fmt, ...)
1926{
1927	char *buf, *p, *next;
1928	int rval;
1929	va_list ap;
1930
1931	va_start(ap, fmt);
1932	rval = vasprintf(&buf, fmt, ap);
1933	va_end(ap);
1934	if (rval == -1 || buf == NULL) {
1935		printf("412 Local resource failure: malloc\r\n");
1936		fflush(stdout);
1937		dologout(1);
1938	}
1939	next = buf;
1940	while ((p = strsep(&next, "\n\r"))) {
1941		printf("%d%s %s\r\n", n, (next != '\0') ? "-" : "", p);
1942		if (debug)
1943			syslog(LOG_DEBUG, "<--- %d%s %s", n,
1944			    (next != '\0') ? "-" : "", p);
1945	}
1946	(void)fflush(stdout);
1947	free(buf);
1948}
1949
1950
1951void
1952reply_r(int n, const char *fmt, ...)
1953{
1954	char *p, *next;
1955	char msg[BUFSIZ];
1956	char buf[BUFSIZ];
1957	va_list ap;
1958	struct syslog_data sdata = SYSLOG_DATA_INIT;
1959
1960	va_start(ap, fmt);
1961	vsnprintf(msg, sizeof(msg), fmt, ap);
1962	va_end(ap);
1963
1964	next = msg;
1965
1966	while ((p = strsep(&next, "\n\r"))) {
1967		snprintf(buf, sizeof(buf), "%d%s %s\r\n", n,
1968		    (next != '\0') ? "-" : "", p);
1969		write(STDOUT_FILENO, buf, strlen(buf));
1970		if (debug) {
1971			buf[strlen(buf) - 2] = '\0';
1972			syslog_r(LOG_DEBUG, &sdata, "<--- %s", buf);
1973		}
1974	}
1975}
1976
1977void
1978lreply(int n, const char *fmt, ...)
1979{
1980	va_list ap;
1981
1982	va_start(ap, fmt);
1983	(void)printf("%d- ", n);
1984	(void)vprintf(fmt, ap);
1985	va_end(ap);
1986	(void)printf("\r\n");
1987	(void)fflush(stdout);
1988	if (debug) {
1989		va_start(ap, fmt);
1990		syslog(LOG_DEBUG, "<--- %d- ", n);
1991		vsyslog(LOG_DEBUG, fmt, ap);
1992		va_end(ap);
1993	}
1994}
1995
1996static void
1997ack(char *s)
1998{
1999
2000	reply(250, "%s command successful.", s);
2001}
2002
2003void
2004nack(char *s)
2005{
2006
2007	reply(502, "%s command not implemented.", s);
2008}
2009
2010/* ARGSUSED */
2011void
2012yyerror(char *s)
2013{
2014	char *cp;
2015
2016	if ((cp = strchr(cbuf,'\n')))
2017		*cp = '\0';
2018	reply(500, "'%s': command not understood.", cbuf);
2019}
2020
2021void
2022delete(char *name)
2023{
2024	struct stat st;
2025
2026	LOGCMD("delete", name);
2027	if (stat(name, &st) < 0) {
2028		perror_reply(550, name);
2029		return;
2030	}
2031	if ((st.st_mode&S_IFMT) == S_IFDIR) {
2032		if (rmdir(name) < 0) {
2033			perror_reply(550, name);
2034			return;
2035		}
2036		goto done;
2037	}
2038	if (unlink(name) < 0) {
2039		perror_reply(550, name);
2040		return;
2041	}
2042done:
2043	ack("DELE");
2044}
2045
2046void
2047cwd(char *path)
2048{
2049	FILE *message;
2050
2051	if (chdir(path) < 0)
2052		perror_reply(550, path);
2053	else {
2054		if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) {
2055			char *cp, line[LINE_MAX];
2056
2057			while (fgets(line, sizeof(line), message) != NULL) {
2058				if ((cp = strchr(line, '\n')) != NULL)
2059					*cp = '\0';
2060				lreply(250, "%s", line);
2061			}
2062			(void) fflush(stdout);
2063			(void) fclose(message);
2064		}
2065		ack("CWD");
2066	}
2067}
2068
2069void
2070replydirname(const char *name, const char *message)
2071{
2072	char *p, *ep;
2073	char npath[MAXPATHLEN * 2];
2074
2075	p = npath;
2076	ep = &npath[sizeof(npath) - 1];
2077	while (*name) {
2078		if (*name == '"') {
2079			if (ep - p < 2)
2080				break;
2081			*p++ = *name++;
2082			*p++ = '"';
2083		} else {
2084			if (ep - p < 1)
2085				break;
2086			*p++ = *name++;
2087		}
2088	}
2089	*p = '\0';
2090	reply(257, "\"%s\" %s", npath, message);
2091}
2092
2093void
2094makedir(char *name)
2095{
2096
2097	LOGCMD("mkdir", name);
2098	if (mkdir(name, 0777) < 0)
2099		perror_reply(550, name);
2100	else
2101		replydirname(name, "directory created.");
2102}
2103
2104void
2105removedir(char *name)
2106{
2107
2108	LOGCMD("rmdir", name);
2109	if (rmdir(name) < 0)
2110		perror_reply(550, name);
2111	else
2112		ack("RMD");
2113}
2114
2115void
2116pwd(void)
2117{
2118	char path[MAXPATHLEN];
2119
2120	if (getcwd(path, sizeof(path)) == NULL)
2121		perror_reply(550, "Can't get current directory");
2122	else
2123		replydirname(path, "is current directory.");
2124}
2125
2126char *
2127renamefrom(char *name)
2128{
2129	struct stat st;
2130
2131	if (stat(name, &st) < 0) {
2132		perror_reply(550, name);
2133		return ((char *)0);
2134	}
2135	reply(350, "File exists, ready for destination name");
2136	return (name);
2137}
2138
2139void
2140renamecmd(char *from, char *to)
2141{
2142
2143	LOGCMD2("rename", from, to);
2144	if (rename(from, to) < 0)
2145		perror_reply(550, "rename");
2146	else
2147		ack("RNTO");
2148}
2149
2150static void
2151dolog(struct sockaddr *sa)
2152{
2153	char hbuf[sizeof(remotehost)];
2154
2155	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0) == 0)
2156		(void) strlcpy(remotehost, hbuf, sizeof(remotehost));
2157	else
2158		(void) strlcpy(remotehost, "unknown", sizeof(remotehost));
2159
2160#ifdef HASSETPROCTITLE
2161	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2162	setproctitle("%s", proctitle);
2163#endif /* HASSETPROCTITLE */
2164
2165	if (logging)
2166		syslog(LOG_INFO, "connection from %s", remotehost);
2167}
2168
2169/*
2170 * Record logout in wtmp file and exit with supplied status.
2171 * NOTE: because this is called from signal handlers it cannot
2172 *       use stdio (or call other functions that use stdio).
2173 */
2174void
2175dologout(int status)
2176{
2177
2178	transflag = 0;
2179
2180	if (logged_in) {
2181		sigprocmask(SIG_BLOCK, &allsigs, NULL);
2182		ftpdlogwtmp(ttyline, "", "");
2183		if (doutmp)
2184			ftpd_logout(utmp.ut_line);
2185	}
2186	/* beware of flushing buffers after a SIGPIPE */
2187	_exit(status);
2188}
2189
2190static void
2191sigurg(int signo)
2192{
2193
2194	recvurg = 1;
2195}
2196
2197static void
2198myoob(void)
2199{
2200	char *cp;
2201
2202	/* only process if transfer occurring */
2203	if (!transflag)
2204		return;
2205	cp = tmpline;
2206	if (getline(cp, 7, stdin) == NULL) {
2207		reply(221, "You could at least say goodbye.");
2208		dologout(0);
2209	}
2210	upper(cp);
2211	if (strcmp(cp, "ABOR\r\n") == 0) {
2212		tmpline[0] = '\0';
2213		reply(426, "Transfer aborted. Data connection closed.");
2214		reply(226, "Abort successful");
2215	}
2216	if (strcmp(cp, "STAT\r\n") == 0) {
2217		tmpline[0] = '\0';
2218		if (file_size != (off_t) -1)
2219			reply(213, "Status: %qd of %qd bytes transferred",
2220			    byte_count, file_size);
2221		else
2222			reply(213, "Status: %qd bytes transferred", byte_count);
2223	}
2224}
2225
2226/*
2227 * Note: a response of 425 is not mentioned as a possible response to
2228 *	the PASV command in RFC959. However, it has been blessed as
2229 *	a legitimate response by Jon Postel in a telephone conversation
2230 *	with Rick Adams on 25 Jan 89.
2231 */
2232void
2233passive(void)
2234{
2235	socklen_t len;
2236	int on;
2237	u_char *p, *a;
2238
2239	if (pw == NULL) {
2240		reply(530, "Please login with USER and PASS");
2241		return;
2242	}
2243	if (pdata >= 0)
2244		close(pdata);
2245	/*
2246	 * XXX
2247	 * At this point, it would be nice to have an algorithm that
2248	 * inserted a growing delay in an attack scenario.  Such a thing
2249	 * would look like continual passive sockets being opened, but
2250	 * nothing serious being done with them.  They're not used to
2251	 * move data; the entire attempt is just to use tcp FIN_WAIT
2252	 * resources.
2253	 */
2254	pdata = socket(AF_INET, SOCK_STREAM, 0);
2255	if (pdata < 0) {
2256		perror_reply(425, "Can't open passive connection");
2257		return;
2258	}
2259
2260	on = IP_PORTRANGE_HIGH;
2261	if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2262	    (char *)&on, sizeof(on)) < 0)
2263		goto pasv_error;
2264
2265	pasv_addr = ctrl_addr;
2266	pasv_addr.su_sin.sin_port = 0;
2267	if (bind(pdata, (struct sockaddr *)&pasv_addr,
2268		 pasv_addr.su_len) < 0)
2269		goto pasv_error;
2270
2271	len = sizeof(pasv_addr);
2272	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2273		goto pasv_error;
2274	if (listen(pdata, 1) < 0)
2275		goto pasv_error;
2276	a = (u_char *) &pasv_addr.su_sin.sin_addr;
2277	p = (u_char *) &pasv_addr.su_sin.sin_port;
2278
2279	reply(227, "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", a[0],
2280	    a[1], a[2], a[3], p[0], p[1]);
2281	return;
2282
2283pasv_error:
2284	(void) close(pdata);
2285	pdata = -1;
2286	perror_reply(425, "Can't open passive connection");
2287	return;
2288}
2289
2290/*
2291 * convert protocol identifier to/from AF
2292 */
2293int
2294lpsvproto2af(int proto)
2295{
2296
2297	switch (proto) {
2298	case 4:	return AF_INET;
2299#ifdef INET6
2300	case 6:	return AF_INET6;
2301#endif
2302	default: return -1;
2303	}
2304}
2305
2306int
2307af2lpsvproto(int af)
2308{
2309
2310	switch (af) {
2311	case AF_INET:	return 4;
2312#ifdef INET6
2313	case AF_INET6:	return 6;
2314#endif
2315	default:	return -1;
2316	}
2317}
2318
2319int
2320epsvproto2af(int proto)
2321{
2322
2323	switch (proto) {
2324	case 1:	return AF_INET;
2325#ifdef INET6
2326	case 2:	return AF_INET6;
2327#endif
2328	default: return -1;
2329	}
2330}
2331
2332int
2333af2epsvproto(int af)
2334{
2335
2336	switch (af) {
2337	case AF_INET:	return 1;
2338#ifdef INET6
2339	case AF_INET6:	return 2;
2340#endif
2341	default:	return -1;
2342	}
2343}
2344
2345/*
2346 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2347 * 229 Entering Extended Passive Mode (|||port|)
2348 */
2349void
2350long_passive(char *cmd, int pf)
2351{
2352	socklen_t len;
2353	int on;
2354	u_char *p, *a;
2355
2356	if (!logged_in) {
2357		syslog(LOG_NOTICE, "long passive but not logged in");
2358		reply(503, "Login with USER first.");
2359		return;
2360	}
2361
2362	if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
2363		/*
2364		 * XXX
2365		 * only EPRT/EPSV ready clients will understand this
2366		 */
2367		if (strcmp(cmd, "EPSV") != 0)
2368			reply(501, "Network protocol mismatch"); /*XXX*/
2369		else
2370			epsv_protounsupp("Network protocol mismatch");
2371
2372		return;
2373	}
2374
2375	if (pdata >= 0)
2376		close(pdata);
2377	/*
2378	 * XXX
2379	 * At this point, it would be nice to have an algorithm that
2380	 * inserted a growing delay in an attack scenario.  Such a thing
2381	 * would look like continual passive sockets being opened, but
2382	 * nothing serious being done with them.  They not used to move
2383	 * data; the entire attempt is just to use tcp FIN_WAIT
2384	 * resources.
2385	 */
2386	pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2387	if (pdata < 0) {
2388		perror_reply(425, "Can't open passive connection");
2389		return;
2390	}
2391
2392	switch (ctrl_addr.su_family) {
2393	case AF_INET:
2394		on = IP_PORTRANGE_HIGH;
2395		if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE,
2396		    (char *)&on, sizeof(on)) < 0)
2397			goto pasv_error;
2398		break;
2399	case AF_INET6:
2400		on = IPV6_PORTRANGE_HIGH;
2401		if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE,
2402		    (char *)&on, sizeof(on)) < 0)
2403			goto pasv_error;
2404		break;
2405	}
2406
2407	pasv_addr = ctrl_addr;
2408	pasv_addr.su_port = 0;
2409	if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0)
2410		goto pasv_error;
2411	len = pasv_addr.su_len;
2412	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2413		goto pasv_error;
2414	if (listen(pdata, 1) < 0)
2415		goto pasv_error;
2416	p = (u_char *) &pasv_addr.su_port;
2417
2418	if (strcmp(cmd, "LPSV") == 0) {
2419		switch (pasv_addr.su_family) {
2420		case AF_INET:
2421			a = (u_char *) &pasv_addr.su_sin.sin_addr;
2422			reply(228,
2423			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2424			    4, 4, a[0], a[1], a[2], a[3], 2, p[0], p[1]);
2425			return;
2426		case AF_INET6:
2427			a = (u_char *) &pasv_addr.su_sin6.sin6_addr;
2428			reply(228,
2429			    "Entering Long Passive Mode (%u,%u,%u,%u,%u,%u,"
2430			    "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u)",
2431				6, 16, a[0], a[1], a[2], a[3], a[4],
2432				a[5], a[6], a[7], a[8], a[9], a[10],
2433				a[11], a[12], a[13], a[14], a[15],
2434				2, p[0], p[1]);
2435			return;
2436		}
2437	} else if (strcmp(cmd, "EPSV") == 0) {
2438		switch (pasv_addr.su_family) {
2439		case AF_INET:
2440		case AF_INET6:
2441			reply(229, "Entering Extended Passive Mode (|||%u|)",
2442			    ntohs(pasv_addr.su_port));
2443			return;
2444		}
2445	} else {
2446		/* more proper error code? */
2447	}
2448
2449  pasv_error:
2450	(void) close(pdata);
2451	pdata = -1;
2452	perror_reply(425, "Can't open passive connection");
2453	return;
2454}
2455
2456/*
2457 * EPRT |proto|addr|port|
2458 */
2459int
2460extended_port(const char *arg)
2461{
2462	char *tmp = NULL;
2463	char *result[3];
2464	char *p, *q;
2465	char delim;
2466	struct addrinfo hints;
2467	struct addrinfo *res = NULL;
2468	int i;
2469	unsigned long proto;
2470
2471	if (epsvall) {
2472		reply(501, "EPRT disallowed after EPSV ALL");
2473		return -1;
2474	}
2475
2476	usedefault = 0;
2477	if (pdata >= 0) {
2478		(void) close(pdata);
2479		pdata = -1;
2480	}
2481
2482	tmp = strdup(arg);
2483	if (!tmp) {
2484		fatal("not enough core.");
2485		/*NOTREACHED*/
2486	}
2487	p = tmp;
2488	delim = p[0];
2489	p++;
2490	memset(result, 0, sizeof(result));
2491	for (i = 0; i < 3; i++) {
2492		q = strchr(p, delim);
2493		if (!q || *q != delim)
2494			goto parsefail;
2495		*q++ = '\0';
2496		result[i] = p;
2497		p = q;
2498	}
2499
2500	/* some more sanity check */
2501	p = NULL;
2502	(void)strtoul(result[2], &p, 10);
2503	if (!*result[2] || *p)
2504		goto protounsupp;
2505	p = NULL;
2506	proto = strtoul(result[0], &p, 10);
2507	if (!*result[0] || *p)
2508		goto protounsupp;
2509
2510	memset(&hints, 0, sizeof(hints));
2511	hints.ai_family = epsvproto2af((int)proto);
2512	if (hints.ai_family < 0)
2513		goto protounsupp;
2514	hints.ai_socktype = SOCK_STREAM;
2515	hints.ai_flags = AI_NUMERICHOST;	/*no DNS*/
2516	if (getaddrinfo(result[1], result[2], &hints, &res))
2517		goto parsefail;
2518	if (res->ai_next)
2519		goto parsefail;
2520	if (sizeof(data_dest) < res->ai_addrlen)
2521		goto parsefail;
2522	memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
2523	if (his_addr.su_family == AF_INET6 &&
2524	    data_dest.su_family == AF_INET6) {
2525		/* XXX more sanity checks! */
2526		data_dest.su_sin6.sin6_scope_id =
2527		    his_addr.su_sin6.sin6_scope_id;
2528	}
2529	if (pdata >= 0) {
2530		(void) close(pdata);
2531		pdata = -1;
2532	}
2533	reply(200, "EPRT command successful.");
2534
2535	if (tmp)
2536		free(tmp);
2537	if (res)
2538		freeaddrinfo(res);
2539	return 0;
2540
2541parsefail:
2542	reply(500, "Invalid argument, rejected.");
2543	usedefault = 1;
2544	if (tmp)
2545		free(tmp);
2546	if (res)
2547		freeaddrinfo(res);
2548	return -1;
2549
2550protounsupp:
2551	epsv_protounsupp("Protocol not supported");
2552	usedefault = 1;
2553	if (tmp)
2554		free(tmp);
2555	if (res)
2556		freeaddrinfo(res);
2557	return -1;
2558}
2559
2560/*
2561 * 522 Protocol not supported (proto,...)
2562 * as we assume address family for control and data connections are the same,
2563 * we do not return the list of address families we support - instead, we
2564 * return the address family of the control connection.
2565 */
2566void
2567epsv_protounsupp(const char *message)
2568{
2569	int proto;
2570
2571	proto = af2epsvproto(ctrl_addr.su_family);
2572	if (proto < 0)
2573		reply(501, "%s", message);	/*XXX*/
2574	else
2575		reply(522, "%s, use (%d)", message, proto);
2576}
2577
2578/*
2579 * Generate unique name for file with basename "local".
2580 * The file named "local" is already known to exist.
2581 * Generates failure reply on error.
2582 */
2583static int
2584guniquefd(char *local, char **nam)
2585{
2586	static char new[MAXPATHLEN];
2587	struct stat st;
2588	int count, len, fd;
2589	char *cp;
2590
2591	cp = strrchr(local, '/');
2592	if (cp)
2593		*cp = '\0';
2594	if (stat(cp ? local : ".", &st) < 0) {
2595		perror_reply(553, cp ? local : ".");
2596		return (-1);
2597	}
2598	if (cp)
2599		*cp = '/';
2600	len = strlcpy(new, local, sizeof(new));
2601	if (len+2+1 >= sizeof(new)-1)
2602		return (-1);
2603	cp = new + len;
2604	*cp++ = '.';
2605	for (count = 1; count < 100; count++) {
2606		(void)snprintf(cp, sizeof(new) - (cp - new), "%d", count);
2607		fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666);
2608		if (fd == -1)
2609			continue;
2610		if (nam)
2611			*nam = new;
2612		return (fd);
2613	}
2614	reply(452, "Unique file name cannot be created.");
2615	return (-1);
2616}
2617
2618/*
2619 * Format and send reply containing system error number.
2620 */
2621void
2622perror_reply(int code, char *string)
2623{
2624
2625	reply(code, "%s: %s.", string, strerror(errno));
2626}
2627
2628static char *onefile[] = {
2629	"",
2630	0
2631};
2632
2633void
2634send_file_list(char *whichf)
2635{
2636	struct stat st;
2637	DIR *dirp = NULL;
2638	struct dirent *dir;
2639	FILE *dout = NULL;
2640	char **dirlist;
2641	char *dirname;
2642	int simple = 0;
2643	volatile int freeglob = 0;
2644	glob_t gl;
2645
2646	if (strpbrk(whichf, "~{[*?") != NULL) {
2647		memset(&gl, 0, sizeof(gl));
2648		freeglob = 1;
2649		if (glob(whichf,
2650		    GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|GLOB_LIMIT,
2651		    0, &gl)) {
2652			reply(550, "not found");
2653			goto out;
2654		} else if (gl.gl_pathc == 0) {
2655			errno = ENOENT;
2656			perror_reply(550, whichf);
2657			goto out;
2658		}
2659		dirlist = gl.gl_pathv;
2660	} else {
2661		onefile[0] = whichf;
2662		dirlist = onefile;
2663		simple = 1;
2664	}
2665
2666	while ((dirname = *dirlist++)) {
2667		if (stat(dirname, &st) < 0) {
2668			/*
2669			 * If user typed "ls -l", etc, and the client
2670			 * used NLST, do what the user meant.
2671			 */
2672			if (dirname[0] == '-' && *dirlist == NULL &&
2673			    transflag == 0) {
2674				retrieve("/bin/ls %s", dirname);
2675				goto out;
2676			}
2677			perror_reply(550, whichf);
2678			if (dout != NULL) {
2679				(void) fclose(dout);
2680				transflag = 0;
2681				data = -1;
2682				pdata = -1;
2683			}
2684			goto out;
2685		}
2686
2687		if (S_ISREG(st.st_mode)) {
2688			if (dout == NULL) {
2689				dout = dataconn("file list", (off_t)-1, "w");
2690				if (dout == NULL)
2691					goto out;
2692				transflag++;
2693			}
2694			fprintf(dout, "%s%s\n", dirname,
2695				type == TYPE_A ? "\r" : "");
2696			byte_count += strlen(dirname) + 1;
2697			continue;
2698		} else if (!S_ISDIR(st.st_mode))
2699			continue;
2700
2701		if ((dirp = opendir(dirname)) == NULL)
2702			continue;
2703
2704		while ((dir = readdir(dirp)) != NULL) {
2705			char nbuf[MAXPATHLEN];
2706
2707			if (recvurg) {
2708				myoob();
2709				recvurg = 0;
2710				transflag = 0;
2711				goto out;
2712			}
2713
2714			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2715				continue;
2716			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2717			    dir->d_namlen == 2)
2718				continue;
2719
2720			snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname,
2721				 dir->d_name);
2722
2723			/*
2724			 * We have to do a stat to insure it's
2725			 * not a directory or special file.
2726			 */
2727			if (simple || (stat(nbuf, &st) == 0 &&
2728			    S_ISREG(st.st_mode))) {
2729				if (dout == NULL) {
2730					dout = dataconn("file list", (off_t)-1,
2731						"w");
2732					if (dout == NULL)
2733						goto out;
2734					transflag++;
2735				}
2736				if (nbuf[0] == '.' && nbuf[1] == '/')
2737					fprintf(dout, "%s%s\n", &nbuf[2],
2738						type == TYPE_A ? "\r" : "");
2739				else
2740					fprintf(dout, "%s%s\n", nbuf,
2741						type == TYPE_A ? "\r" : "");
2742				byte_count += strlen(nbuf) + 1;
2743			}
2744		}
2745		(void) closedir(dirp);
2746	}
2747
2748	if (dout == NULL)
2749		reply(550, "No files found.");
2750	else if (ferror(dout) != 0)
2751		perror_reply(550, "Data connection");
2752	else
2753		reply(226, "Transfer complete.");
2754
2755	transflag = 0;
2756	if (dout != NULL)
2757		(void) fclose(dout);
2758	else {
2759		if (pdata >= 0)
2760			close(pdata);
2761	}
2762	data = -1;
2763	pdata = -1;
2764out:
2765	if (freeglob) {
2766		freeglob = 0;
2767		globfree(&gl);
2768	}
2769}
2770
2771static void
2772reapchild(int signo)
2773{
2774	int save_errno = errno;
2775	int rval;
2776
2777	do {
2778		rval = waitpid(-1, NULL, WNOHANG);
2779	} while (rval > 0 || (rval == -1 && errno == EINTR));
2780	errno = save_errno;
2781}
2782
2783void
2784logxfer(char *name, off_t size, time_t start)
2785{
2786	char buf[400 + MAXHOSTNAMELEN*4 + MAXPATHLEN*4];
2787	char dir[MAXPATHLEN], path[MAXPATHLEN], rpath[MAXPATHLEN];
2788	char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4];
2789	char *vpw;
2790	time_t now;
2791	int len;
2792
2793	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
2794		time(&now);
2795
2796		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
2797		if (vpw == NULL)
2798			return;
2799
2800		snprintf(path, sizeof(path), "%s/%s", dir, name);
2801		if (realpath(path, rpath) == NULL)
2802			strlcpy(rpath, path, sizeof(rpath));
2803		strvis(vpath, rpath, VIS_SAFE|VIS_NOSLASH);
2804
2805		strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH);
2806		strvis(vpw, guest? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH);
2807
2808		len = snprintf(buf, sizeof(buf),
2809		    "%.24s %d %s %qd %s %c %s %c %c %s ftp %d %s %s\n",
2810		    ctime(&now), now - start + (now == start),
2811		    vremotehost, (long long)size, vpath,
2812		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
2813		    'o', ((guest) ? 'a' : 'r'),
2814		    vpw, 0 /* none yet */,
2815		    ((guest) ? "*" : pw->pw_name), dhostname);
2816
2817		if (len >= sizeof(buf) || len == -1) {
2818			if ((len = strlen(buf)) == 0)
2819				return;		/* should not happen */
2820			buf[len - 1] = '\n';
2821		}
2822		write(statfd, buf, len);
2823		free(vpw);
2824	}
2825}
2826
2827void
2828set_slave_signals(void)
2829{
2830	struct sigaction sa;
2831
2832	sigemptyset(&sa.sa_mask);
2833	sa.sa_flags = SA_RESTART;
2834
2835	sa.sa_handler = SIG_DFL;
2836	(void) sigaction(SIGCHLD, &sa, NULL);
2837
2838	sa.sa_handler = sigurg;
2839	sa.sa_flags = 0;		/* don't restart syscalls for SIGURG */
2840	(void) sigaction(SIGURG, &sa, NULL);
2841
2842	sigfillset(&sa.sa_mask);	/* block all signals in handler */
2843	sa.sa_flags = SA_RESTART;
2844	sa.sa_handler = sigquit;
2845	(void) sigaction(SIGHUP, &sa, NULL);
2846	(void) sigaction(SIGINT, &sa, NULL);
2847	(void) sigaction(SIGQUIT, &sa, NULL);
2848	(void) sigaction(SIGTERM, &sa, NULL);
2849
2850	sa.sa_handler = lostconn;
2851	(void) sigaction(SIGPIPE, &sa, NULL);
2852
2853	sa.sa_handler = toolong;
2854	(void) sigaction(SIGALRM, &sa, NULL);
2855
2856#ifdef F_SETOWN
2857	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
2858		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
2859#endif
2860}
2861
2862#if defined(TCPWRAPPERS)
2863static int
2864check_host(struct sockaddr *sa)
2865{
2866	struct sockaddr_in *sin;
2867	struct hostent *hp;
2868	char *addr;
2869
2870	if (sa->sa_family != AF_INET)
2871		return 1;	/*XXX*/
2872
2873	sin = (struct sockaddr_in *)sa;
2874	hp = gethostbyaddr((char *)&sin->sin_addr,
2875	    sizeof(struct in_addr), AF_INET);
2876	addr = inet_ntoa(sin->sin_addr);
2877	if (hp) {
2878		if (!hosts_ctl("ftpd", hp->h_name, addr, STRING_UNKNOWN)) {
2879			syslog(LOG_NOTICE, "tcpwrappers rejected: %s [%s]",
2880			    hp->h_name, addr);
2881			return (0);
2882		}
2883	} else {
2884		if (!hosts_ctl("ftpd", STRING_UNKNOWN, addr, STRING_UNKNOWN)) {
2885			syslog(LOG_NOTICE, "tcpwrappers rejected: [%s]", addr);
2886			return (0);
2887		}
2888	}
2889	return (1);
2890}
2891#endif	/* TCPWRAPPERS */
2892
2893/*
2894 * Allocate space and return a copy of the specified dir.
2895 * If 'dir' begins with a tilde (~), expand it.
2896 */
2897char *
2898copy_dir(char *dir, struct passwd *pw)
2899{
2900	char *cp;
2901	char *newdir;
2902	char *user = NULL;
2903	size_t dirsiz;
2904
2905	/* Nothing to expand */
2906	if (dir[0] != '~')
2907		return (strdup(dir));
2908
2909	/* "dir" is of form ~user/some/dir, lookup user. */
2910	if (dir[1] != '/' && dir[1] != '\0') {
2911		if ((cp = strchr(dir + 1, '/')) == NULL)
2912		    cp = dir + strlen(dir);
2913		if ((user = malloc(cp - dir)) == NULL)
2914			return (NULL);
2915		strlcpy(user, dir + 1, cp - dir);
2916
2917		/* Only do lookup if it is a different user. */
2918		if (strcmp(user, pw->pw_name) != 0) {
2919			if ((pw = getpwnam(user)) == NULL) {
2920				/* No such user, interpret literally */
2921				free(user);
2922				return(strdup(dir));
2923			}
2924		}
2925	}
2926
2927	/*
2928	 * If there is no directory separator (/) then it is just pw_dir.
2929	 * Otherwise, replace ~foo with  pw_dir.
2930	 */
2931	if ((cp = strchr(dir + 1, '/')) == NULL) {
2932		newdir = strdup(pw->pw_dir);
2933	} else {
2934		dirsiz = strlen(cp) + strlen(pw->pw_dir) + 1;
2935		if ((newdir = malloc(dirsiz)) == NULL) {
2936			free(user);
2937			return (NULL);
2938		}
2939		strlcpy(newdir, pw->pw_dir, dirsiz);
2940		strlcat(newdir, cp, dirsiz);
2941	}
2942
2943	if (user)
2944		free(user);
2945	return(newdir);
2946}
2947