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