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