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