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