ftpd.c revision 8240
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#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";
42#endif /* not lint */
43
44/*
45 * FTP server.
46 */
47#include <sys/param.h>
48#include <sys/stat.h>
49#include <sys/ioctl.h>
50#include <sys/socket.h>
51#include <sys/wait.h>
52#include <sys/mman.h>
53
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/tcp.h>
58
59#define	FTP_NAMES
60#include <arpa/ftp.h>
61#include <arpa/inet.h>
62#include <arpa/telnet.h>
63
64#include <ctype.h>
65#include <dirent.h>
66#include <err.h>
67#include <errno.h>
68#include <fcntl.h>
69#include <glob.h>
70#include <limits.h>
71#include <netdb.h>
72#include <pwd.h>
73#include <setjmp.h>
74#include <signal.h>
75#include <stdio.h>
76#include <stdlib.h>
77#include <string.h>
78#include <syslog.h>
79#include <time.h>
80#include <unistd.h>
81
82#ifdef	SKEY
83#include <skey.h>
84#endif
85
86#include "pathnames.h"
87#include "extern.h"
88
89#if __STDC__
90#include <stdarg.h>
91#else
92#include <varargs.h>
93#endif
94
95static char version[] = "Version 6.00";
96
97extern	off_t restart_point;
98extern	char cbuf[];
99
100struct	sockaddr_in ctrl_addr;
101struct	sockaddr_in data_source;
102struct	sockaddr_in data_dest;
103struct	sockaddr_in his_addr;
104struct	sockaddr_in pasv_addr;
105
106int	data;
107jmp_buf	errcatch, urgcatch;
108int	logged_in;
109struct	passwd *pw;
110int	debug;
111int	timeout = 900;    /* timeout after 15 minutes of inactivity */
112int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
113int	logging;
114int	guest;
115#ifdef STATS
116int	stats;
117int	statfd = -1;
118#endif
119int	type;
120int	form;
121int	stru;			/* avoid C keyword */
122int	mode;
123int	usedefault = 1;		/* for data transfers */
124int	pdata = -1;		/* for passive mode */
125sig_atomic_t transflag;
126off_t	file_size;
127off_t	byte_count;
128#if !defined(CMASK) || CMASK == 0
129#undef CMASK
130#define CMASK 027
131#endif
132int	defumask = CMASK;		/* default umask value */
133char	tmpline[7];
134char	hostname[MAXHOSTNAMELEN];
135char	remotehost[MAXHOSTNAMELEN];
136#ifdef STATS
137char	*ident = NULL;
138#endif
139
140/*
141 * Timeout intervals for retrying connections
142 * to hosts that don't accept PORT cmds.  This
143 * is a kludge, but given the problems with TCP...
144 */
145#define	SWAITMAX	90	/* wait at most 90 seconds */
146#define	SWAITINT	5	/* interval between retries */
147
148int	swaitmax = SWAITMAX;
149int	swaitint = SWAITINT;
150
151#ifdef SETPROCTITLE
152char	**Argv = NULL;		/* pointer to argument vector */
153char	*LastArgv = NULL;	/* end of argv */
154char	proctitle[LINE_MAX];	/* initial part of title */
155#endif /* SETPROCTITLE */
156
157#ifdef SKEY
158int	pwok = 0;
159char	addr_string[20];	/* XXX */
160#endif
161
162#define LOGCMD(cmd, file) \
163	if (logging > 1) \
164	    syslog(LOG_INFO,"%s %s%s", cmd, \
165		*(file) == '/' ? "" : curdir(), file);
166#define LOGCMD2(cmd, file1, file2) \
167	 if (logging > 1) \
168	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
169		*(file1) == '/' ? "" : curdir(), file1, \
170		*(file2) == '/' ? "" : curdir(), file2);
171#define LOGBYTES(cmd, file, cnt) \
172	if (logging > 1) { \
173		if (cnt == (off_t)-1) \
174		    syslog(LOG_INFO,"%s %s%s", cmd, \
175			*(file) == '/' ? "" : curdir(), file); \
176		else \
177		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \
178			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
179	}
180
181static void	 ack __P((char *));
182static void	 myoob __P((int));
183static int	 checkuser __P((char *));
184static FILE	*dataconn __P((char *, off_t, char *));
185static void	 dolog __P((struct sockaddr_in *));
186static char	*curdir __P((void));
187static void	 end_login __P((void));
188static FILE	*getdatasock __P((char *));
189static char	*gunique __P((char *));
190static void	 lostconn __P((int));
191static int	 receive_data __P((FILE *, FILE *));
192static void	 send_data __P((FILE *, FILE *, off_t, off_t, int));
193static struct passwd *
194		 sgetpwnam __P((char *));
195static char	*sgetsave __P((char *));
196
197static char *
198curdir()
199{
200	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */
201
202	if (getcwd(path, sizeof(path)-2) == NULL)
203		return ("");
204	if (path[1] != '\0')		/* special case for root dir. */
205		strcat(path, "/");
206	/* For guest account, skip / since it's chrooted */
207	return (guest ? path+1 : path);
208}
209
210int
211main(argc, argv, envp)
212	int argc;
213	char *argv[];
214	char **envp;
215{
216	int addrlen, ch, on = 1, tos;
217	char *cp, line[LINE_MAX];
218	FILE *fd;
219
220	tzset();		/* in case no timezone database in ~ftp */
221
222	/*
223	 * LOG_NDELAY sets up the logging connection immediately,
224	 * necessary for anonymous ftp's that chroot and can't do it later.
225	 */
226	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
227	addrlen = sizeof(his_addr);
228	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
229		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
230		exit(1);
231	}
232#ifdef SKEY
233	strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
234#endif
235	addrlen = sizeof(ctrl_addr);
236	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
237		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
238		exit(1);
239	}
240#ifdef IP_TOS
241	tos = IPTOS_LOWDELAY;
242	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
243		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
244#endif
245	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
246	debug = 0;
247#ifdef SETPROCTITLE
248	/*
249	 *  Save start and extent of argv for setproctitle.
250	 */
251	Argv = argv;
252	while (*envp)
253		envp++;
254	LastArgv = envp[-1] + strlen(envp[-1]);
255#endif /* SETPROCTITLE */
256
257
258#ifdef STATS
259	while ((ch = getopt(argc, argv, "dlSt:T:u:v")) != EOF) {
260#else
261	while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
262#endif
263		switch (ch) {
264		case 'd':
265			debug = 1;
266			break;
267
268		case 'l':
269			logging++;	/* > 1 == extra logging */
270			break;
271
272		case 't':
273			timeout = atoi(optarg);
274			if (maxtimeout < timeout)
275				maxtimeout = timeout;
276			break;
277#ifdef STATS
278		case 'S':
279			stats =  1;
280			break;
281#endif
282		case 'T':
283			maxtimeout = atoi(optarg);
284			if (timeout > maxtimeout)
285				timeout = maxtimeout;
286			break;
287
288		case 'u':
289		    {
290			long val = 0;
291
292			val = strtol(optarg, &optarg, 8);
293			if (*optarg != '\0' || val < 0)
294				warnx("bad value for -u");
295			else
296				defumask = val;
297			break;
298		    }
299
300		case 'v':
301			debug = 1;
302			break;
303
304		default:
305			warnx("unknown flag -%c ignored", optopt);
306			break;
307		}
308	}
309	(void) freopen(_PATH_DEVNULL, "w", stderr);
310	(void) signal(SIGPIPE, lostconn);
311	(void) signal(SIGCHLD, SIG_IGN);
312	if ((int)signal(SIGURG, myoob) < 0)
313		syslog(LOG_ERR, "signal: %m");
314
315	/* Try to handle urgent data inline */
316#ifdef SO_OOBINLINE
317	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
318		syslog(LOG_ERR, "setsockopt: %m");
319#endif
320
321#ifdef	F_SETOWN
322	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
323		syslog(LOG_ERR, "fcntl F_SETOWN: %m");
324#endif
325	dolog(&his_addr);
326	/*
327	 * Set up default state
328	 */
329	data = -1;
330	type = TYPE_A;
331	form = FORM_N;
332	stru = STRU_F;
333	mode = MODE_S;
334	tmpline[0] = '\0';
335
336	/* If logins are disabled, print out the message. */
337	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
338		while (fgets(line, sizeof(line), fd) != NULL) {
339			if ((cp = strchr(line, '\n')) != NULL)
340				*cp = '\0';
341			lreply(530, "%s", line);
342		}
343		(void) fflush(stdout);
344		(void) fclose(fd);
345		reply(530, "System not available.");
346		exit(0);
347	}
348	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
349		while (fgets(line, sizeof(line), fd) != NULL) {
350			if ((cp = strchr(line, '\n')) != NULL)
351				*cp = '\0';
352			lreply(220, "%s", line);
353		}
354		(void) fflush(stdout);
355		(void) fclose(fd);
356		/* reply(220,) must follow */
357	}
358	(void) gethostname(hostname, sizeof(hostname));
359	reply(220, "%s FTP server (%s) ready.", hostname, version);
360	(void) setjmp(errcatch);
361	for (;;)
362		(void) yyparse();
363	/* NOTREACHED */
364}
365
366static void
367lostconn(signo)
368	int signo;
369{
370
371	if (debug)
372		syslog(LOG_DEBUG, "lost connection");
373	dologout(-1);
374}
375
376static char ttyline[20];
377
378/*
379 * Helper function for sgetpwnam().
380 */
381static char *
382sgetsave(s)
383	char *s;
384{
385	char *new = malloc((unsigned) strlen(s) + 1);
386
387	if (new == NULL) {
388		perror_reply(421, "Local resource failure: malloc");
389		dologout(1);
390		/* NOTREACHED */
391	}
392	(void) strcpy(new, s);
393	return (new);
394}
395
396/*
397 * Save the result of a getpwnam.  Used for USER command, since
398 * the data returned must not be clobbered by any other command
399 * (e.g., globbing).
400 */
401static struct passwd *
402sgetpwnam(name)
403	char *name;
404{
405	static struct passwd save;
406	struct passwd *p;
407
408	if ((p = getpwnam(name)) == NULL)
409		return (p);
410	if (save.pw_name) {
411		free(save.pw_name);
412		free(save.pw_passwd);
413		free(save.pw_gecos);
414		free(save.pw_dir);
415		free(save.pw_shell);
416	}
417	save = *p;
418	save.pw_name = sgetsave(p->pw_name);
419	save.pw_passwd = sgetsave(p->pw_passwd);
420	save.pw_gecos = sgetsave(p->pw_gecos);
421	save.pw_dir = sgetsave(p->pw_dir);
422	save.pw_shell = sgetsave(p->pw_shell);
423	return (&save);
424}
425
426static int login_attempts;	/* number of failed login attempts */
427static int askpasswd;		/* had user command, ask for passwd */
428static char curname[10];	/* current USER name */
429
430/*
431 * USER command.
432 * Sets global passwd pointer pw if named account exists and is acceptable;
433 * sets askpasswd if a PASS command is expected.  If logged in previously,
434 * need to reset state.  If name is "ftp" or "anonymous", the name is not in
435 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
436 * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
437 * requesting login privileges.  Disallow anyone who does not have a standard
438 * shell as returned by getusershell().  Disallow anyone mentioned in the file
439 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
440 */
441void
442user(name)
443	char *name;
444{
445	char *cp, *shell;
446
447	if (logged_in) {
448		if (guest) {
449			reply(530, "Can't change user from guest login.");
450			return;
451		}
452		end_login();
453	}
454
455	guest = 0;
456	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
457		if (checkuser("ftp") || checkuser("anonymous"))
458			reply(530, "User %s access denied.", name);
459		else if ((pw = sgetpwnam("ftp")) != NULL) {
460			guest = 1;
461			askpasswd = 1;
462			reply(331,
463			"Guest login ok, send your email address as password.");
464		} else
465			reply(530, "User %s unknown.", name);
466		if (!askpasswd && logging)
467			syslog(LOG_NOTICE,
468			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
469		return;
470	}
471	if (pw = sgetpwnam(name)) {
472		if ((shell = pw->pw_shell) == NULL || *shell == 0)
473			shell = _PATH_BSHELL;
474		while ((cp = getusershell()) != NULL)
475			if (strcmp(cp, shell) == 0)
476				break;
477		endusershell();
478
479		if (cp == NULL || checkuser(name)) {
480			reply(530, "User %s access denied.", name);
481			if (logging)
482				syslog(LOG_NOTICE,
483				    "FTP LOGIN REFUSED FROM %s, %s",
484				    remotehost, name);
485			pw = (struct passwd *) NULL;
486			return;
487		}
488	}
489	if (logging)
490		strncpy(curname, name, sizeof(curname)-1);
491#ifdef SKEY
492	pwok = skeyaccess(name, NULL, remotehost, addr_string);
493	reply(331, "%s", skey_challenge(name, pw, pwok));
494#else
495	reply(331, "Password required for %s.", name);
496#endif
497	askpasswd = 1;
498	/*
499	 * Delay before reading passwd after first failed
500	 * attempt to slow down passwd-guessing programs.
501	 */
502	if (login_attempts)
503		sleep((unsigned) login_attempts);
504}
505
506/*
507 * Check if a user is in the file _PATH_FTPUSERS
508 */
509static int
510checkuser(name)
511	char *name;
512{
513	FILE *fd;
514	int found = 0;
515	char *p, line[BUFSIZ];
516
517	if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
518		while (fgets(line, sizeof(line), fd) != NULL)
519			if ((p = strchr(line, '\n')) != NULL) {
520				*p = '\0';
521				if (line[0] == '#')
522					continue;
523				if (strcmp(line, name) == 0) {
524					found = 1;
525					break;
526				}
527			}
528		(void) fclose(fd);
529	}
530	return (found);
531}
532
533/*
534 * Terminate login as previous user, if any, resetting state;
535 * used when USER command is given or login fails.
536 */
537static void
538end_login()
539{
540
541	(void) seteuid((uid_t)0);
542	if (logged_in)
543		logwtmp(ttyline, "", "");
544	pw = NULL;
545	logged_in = 0;
546	guest = 0;
547}
548
549void
550pass(passwd)
551	char *passwd;
552{
553	char *salt, *xpasswd;
554	FILE *fd;
555
556	if (logged_in || askpasswd == 0) {
557		reply(503, "Login with USER first.");
558		return;
559	}
560	askpasswd = 0;
561	if (!guest) {		/* "ftp" is only account allowed no password */
562		if (pw == NULL)
563			salt = "xx";
564		else
565			salt = pw->pw_passwd;
566#ifdef SKEY
567		xpasswd = skey_crypt(passwd, salt, pw, pwok);
568		pwok = 0;
569#else
570		xpasswd = crypt(passwd, salt);
571#endif
572		/* The strcmp does not catch null passwords! */
573		if (pw == NULL || *pw->pw_passwd == '\0' ||
574		    strcmp(xpasswd, pw->pw_passwd)) {
575			reply(530, "Login incorrect.");
576			if (logging)
577				syslog(LOG_NOTICE,
578				    "FTP LOGIN FAILED FROM %s, %s",
579				    remotehost, curname);
580			pw = NULL;
581			if (login_attempts++ >= 5) {
582				syslog(LOG_NOTICE,
583				    "repeated login failures from %s",
584				    remotehost);
585				exit(0);
586			}
587			return;
588		}
589	}
590	login_attempts = 0;		/* this time successful */
591	if (setegid((gid_t)pw->pw_gid) < 0) {
592		reply(550, "Can't set gid.");
593		return;
594	}
595	(void) initgroups(pw->pw_name, pw->pw_gid);
596
597	/* open wtmp before chroot */
598	(void)sprintf(ttyline, "ftp%d", getpid());
599	logwtmp(ttyline, pw->pw_name, remotehost);
600	logged_in = 1;
601
602#ifdef STATS
603	if (guest && stats == 1 && statfd < 0)
604		if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
605			stats = 0;
606#endif
607
608	if (guest) {
609		/*
610		 * We MUST do a chdir() after the chroot. Otherwise
611		 * the old current directory will be accessible as "."
612		 * outside the new root!
613		 */
614		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
615			reply(550, "Can't set guest privileges.");
616			goto bad;
617		}
618	} else if (chdir(pw->pw_dir) < 0) {
619		if (chdir("/") < 0) {
620			reply(530, "User %s: can't change directory to %s.",
621			    pw->pw_name, pw->pw_dir);
622			goto bad;
623		} else
624			lreply(230, "No directory! Logging in with home=/");
625	}
626	if (seteuid((uid_t)pw->pw_uid) < 0) {
627		reply(550, "Can't set uid.");
628		goto bad;
629	}
630	/*
631	 * Display a login message, if it exists.
632	 * N.B. reply(230,) must follow the message.
633	 */
634	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
635		char *cp, line[LINE_MAX];
636
637		while (fgets(line, sizeof(line), fd) != NULL) {
638			if ((cp = strchr(line, '\n')) != NULL)
639				*cp = '\0';
640			lreply(230, "%s", line);
641		}
642		(void) fflush(stdout);
643		(void) fclose(fd);
644	}
645	if (guest) {
646#ifdef STATS
647		char * copy();
648
649		if (ident != NULL)
650			free(ident);
651		ident = (char *) copy(passwd);
652#endif
653		reply(230, "Guest login ok, access restrictions apply.");
654#ifdef SETPROCTITLE
655		snprintf(proctitle, sizeof(proctitle),
656		    "%s: anonymous/%.*s", remotehost,
657		    sizeof(proctitle) - sizeof(remotehost) -
658		    sizeof(": anonymous/"), passwd);
659		setproctitle(proctitle);
660#endif /* SETPROCTITLE */
661		if (logging)
662			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
663			    remotehost, passwd);
664	} else {
665		reply(230, "User %s logged in.", pw->pw_name);
666#ifdef SETPROCTITLE
667		snprintf(proctitle, sizeof(proctitle),
668		    "%s: %s", remotehost, pw->pw_name);
669		setproctitle(proctitle);
670#endif /* SETPROCTITLE */
671		if (logging)
672			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
673			    remotehost, pw->pw_name);
674	}
675	(void) umask(defumask);
676	return;
677bad:
678	/* Forget all about it... */
679	end_login();
680}
681
682void
683retrieve(cmd, name)
684	char *cmd, *name;
685{
686	FILE *fin, *dout;
687	struct stat st;
688	int (*closefunc) __P((FILE *));
689#ifdef STATS
690	long start;
691#endif
692
693	if (cmd == 0) {
694		fin = fopen(name, "r"), closefunc = fclose;
695		st.st_size = 0;
696	} else {
697		char line[BUFSIZ];
698
699		(void) sprintf(line, cmd, name), name = line;
700		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;
701		st.st_size = -1;
702		st.st_blksize = BUFSIZ;
703	}
704	if (fin == NULL) {
705		if (errno != 0) {
706			perror_reply(550, name);
707			if (cmd == 0) {
708				LOGCMD("get", name);
709			}
710		}
711		return;
712	}
713	byte_count = -1;
714	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
715		reply(550, "%s: not a plain file.", name);
716		goto done;
717	}
718	if (restart_point) {
719		if (type == TYPE_A) {
720			off_t i, n;
721			int c;
722
723			n = restart_point;
724			i = 0;
725			while (i++ < n) {
726				if ((c=getc(fin)) == EOF) {
727					perror_reply(550, name);
728					goto done;
729				}
730				if (c == '\n')
731					i++;
732			}
733		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
734			perror_reply(550, name);
735			goto done;
736		}
737	}
738	dout = dataconn(name, st.st_size, "w");
739	if (dout == NULL)
740		goto done;
741#ifdef STATS
742	time(&start);
743#endif
744	send_data(fin, dout, st.st_blksize, st.st_size,
745		  restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode));
746#ifdef STATS
747	if (cmd == 0 && guest && stats)
748		logxfer( name, st.st_size, start);
749#endif
750	(void) fclose(dout);
751	data = -1;
752	pdata = -1;
753done:
754	if (cmd == 0)
755		LOGBYTES("get", name, byte_count);
756	(*closefunc)(fin);
757}
758
759void
760store(name, mode, unique)
761	char *name, *mode;
762	int unique;
763{
764	FILE *fout, *din;
765	struct stat st;
766	int (*closefunc) __P((FILE *));
767
768	if (unique && stat(name, &st) == 0 &&
769	    (name = gunique(name)) == NULL) {
770		LOGCMD(*mode == 'w' ? "put" : "append", name);
771		return;
772	}
773
774	if (restart_point)
775		mode = "r+";
776	fout = fopen(name, mode);
777	closefunc = fclose;
778	if (fout == NULL) {
779		perror_reply(553, name);
780		LOGCMD(*mode == 'w' ? "put" : "append", name);
781		return;
782	}
783	byte_count = -1;
784	if (restart_point) {
785		if (type == TYPE_A) {
786			off_t i, n;
787			int c;
788
789			n = restart_point;
790			i = 0;
791			while (i++ < n) {
792				if ((c=getc(fout)) == EOF) {
793					perror_reply(550, name);
794					goto done;
795				}
796				if (c == '\n')
797					i++;
798			}
799			/*
800			 * We must do this seek to "current" position
801			 * because we are changing from reading to
802			 * writing.
803			 */
804			if (fseek(fout, 0L, L_INCR) < 0) {
805				perror_reply(550, name);
806				goto done;
807			}
808		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
809			perror_reply(550, name);
810			goto done;
811		}
812	}
813	din = dataconn(name, (off_t)-1, "r");
814	if (din == NULL)
815		goto done;
816	if (receive_data(din, fout) == 0) {
817		if (unique)
818			reply(226, "Transfer complete (unique file name:%s).",
819			    name);
820		else
821			reply(226, "Transfer complete.");
822	}
823	(void) fclose(din);
824	data = -1;
825	pdata = -1;
826done:
827	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
828	(*closefunc)(fout);
829}
830
831static FILE *
832getdatasock(mode)
833	char *mode;
834{
835	int on = 1, s, t, tries;
836
837	if (data >= 0)
838		return (fdopen(data, mode));
839	(void) seteuid((uid_t)0);
840	s = socket(AF_INET, SOCK_STREAM, 0);
841	if (s < 0)
842		goto bad;
843	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
844	    (char *) &on, sizeof(on)) < 0)
845		goto bad;
846	/* anchor socket to avoid multi-homing problems */
847	data_source.sin_family = AF_INET;
848	data_source.sin_addr = ctrl_addr.sin_addr;
849	for (tries = 1; ; tries++) {
850		if (bind(s, (struct sockaddr *)&data_source,
851		    sizeof(data_source)) >= 0)
852			break;
853		if (errno != EADDRINUSE || tries > 10)
854			goto bad;
855		sleep(tries);
856	}
857	(void) seteuid((uid_t)pw->pw_uid);
858#ifdef IP_TOS
859	on = IPTOS_THROUGHPUT;
860	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
861		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
862#endif
863#ifdef TCP_NOPUSH
864	/*
865	 * Turn off push flag to keep sender TCP from sending short packets
866	 * at the boundaries of each write().  Should probably do a SO_SNDBUF
867	 * to set the send buffer size as well, but that may not be desirable
868	 * in heavy-load situations.
869	 */
870	on = 1;
871	if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0)
872		syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");
873#endif
874#ifdef SO_SNDBUF
875	on = 65536;
876	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0)
877		syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");
878#endif
879
880	return (fdopen(s, mode));
881bad:
882	/* Return the real value of errno (close may change it) */
883	t = errno;
884	(void) seteuid((uid_t)pw->pw_uid);
885	(void) close(s);
886	errno = t;
887	return (NULL);
888}
889
890static FILE *
891dataconn(name, size, mode)
892	char *name;
893	off_t size;
894	char *mode;
895{
896	char sizebuf[32];
897	FILE *file;
898	int retry = 0, tos;
899
900	file_size = size;
901	byte_count = 0;
902	if (size != (off_t) -1)
903		(void) sprintf(sizebuf, " (%qd bytes)", size);
904	else
905		(void) strcpy(sizebuf, "");
906	if (pdata >= 0) {
907		struct sockaddr_in from;
908		int s, fromlen = sizeof(from);
909
910		s = accept(pdata, (struct sockaddr *)&from, &fromlen);
911		if (s < 0) {
912			reply(425, "Can't open data connection.");
913			(void) close(pdata);
914			pdata = -1;
915			return (NULL);
916		}
917		(void) close(pdata);
918		pdata = s;
919#ifdef IP_TOS
920		tos = IPTOS_LOWDELAY;
921		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
922		    sizeof(int));
923#endif
924		reply(150, "Opening %s mode data connection for '%s'%s.",
925		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
926		return (fdopen(pdata, mode));
927	}
928	if (data >= 0) {
929		reply(125, "Using existing data connection for '%s'%s.",
930		    name, sizebuf);
931		usedefault = 1;
932		return (fdopen(data, mode));
933	}
934	if (usedefault)
935		data_dest = his_addr;
936	usedefault = 1;
937	file = getdatasock(mode);
938	if (file == NULL) {
939		reply(425, "Can't create data socket (%s,%d): %s.",
940		    inet_ntoa(data_source.sin_addr),
941		    ntohs(data_source.sin_port), strerror(errno));
942		return (NULL);
943	}
944	data = fileno(file);
945	while (connect(data, (struct sockaddr *)&data_dest,
946	    sizeof(data_dest)) < 0) {
947		if (errno == EADDRINUSE && retry < swaitmax) {
948			sleep((unsigned) swaitint);
949			retry += swaitint;
950			continue;
951		}
952		perror_reply(425, "Can't build data connection");
953		(void) fclose(file);
954		data = -1;
955		return (NULL);
956	}
957	reply(150, "Opening %s mode data connection for '%s'%s.",
958	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
959	return (file);
960}
961
962/*
963 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
964 * encapsulation of the data subject to Mode, Structure, and Type.
965 *
966 * NB: Form isn't handled.
967 */
968static void
969send_data(instr, outstr, blksize, filesize, isreg)
970	FILE *instr, *outstr;
971	off_t blksize;
972	off_t filesize;
973	int isreg;
974{
975	int c, cnt, filefd, netfd;
976	char *buf, *bp;
977	size_t len;
978
979	transflag++;
980	if (setjmp(urgcatch)) {
981		transflag = 0;
982		return;
983	}
984	switch (type) {
985
986	case TYPE_A:
987		while ((c = getc(instr)) != EOF) {
988			byte_count++;
989			if (c == '\n') {
990				if (ferror(outstr))
991					goto data_err;
992				(void) putc('\r', outstr);
993			}
994			(void) putc(c, outstr);
995		}
996		fflush(outstr);
997		transflag = 0;
998		if (ferror(instr))
999			goto file_err;
1000		if (ferror(outstr))
1001			goto data_err;
1002		reply(226, "Transfer complete.");
1003		return;
1004
1005	case TYPE_I:
1006	case TYPE_L:
1007		/*
1008		 * isreg is only set if we are not doing restart and we
1009		 * are sending a regular file
1010		 */
1011		netfd = fileno(outstr);
1012		filefd = fileno(instr);
1013
1014		if (isreg && filesize < (off_t)16 * 1024 * 1024) {
1015			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,
1016				   (off_t)0);
1017			if (!buf) {
1018				syslog(LOG_WARNING, "mmap(%lu): %m",
1019				       (unsigned long)filesize);
1020				goto oldway;
1021			}
1022			bp = buf;
1023			len = filesize;
1024			do {
1025				cnt = write(netfd, bp, len);
1026				len -= cnt;
1027				bp += cnt;
1028				if (cnt > 0) byte_count += cnt;
1029			} while(cnt > 0 && len > 0);
1030
1031			transflag = 0;
1032			munmap(buf, (size_t)filesize);
1033			if (cnt < 0)
1034				goto data_err;
1035			reply(226, "Transfer complete.");
1036			return;
1037		}
1038
1039oldway:
1040		if ((buf = malloc((u_int)blksize)) == NULL) {
1041			transflag = 0;
1042			perror_reply(451, "Local resource failure: malloc");
1043			return;
1044		}
1045
1046		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1047		    write(netfd, buf, cnt) == cnt)
1048			byte_count += cnt;
1049		transflag = 0;
1050		(void)free(buf);
1051		if (cnt != 0) {
1052			if (cnt < 0)
1053				goto file_err;
1054			goto data_err;
1055		}
1056		reply(226, "Transfer complete.");
1057		return;
1058	default:
1059		transflag = 0;
1060		reply(550, "Unimplemented TYPE %d in send_data", type);
1061		return;
1062	}
1063
1064data_err:
1065	transflag = 0;
1066	perror_reply(426, "Data connection");
1067	return;
1068
1069file_err:
1070	transflag = 0;
1071	perror_reply(551, "Error on input file");
1072}
1073
1074/*
1075 * Transfer data from peer to "outstr" using the appropriate encapulation of
1076 * the data subject to Mode, Structure, and Type.
1077 *
1078 * N.B.: Form isn't handled.
1079 */
1080static int
1081receive_data(instr, outstr)
1082	FILE *instr, *outstr;
1083{
1084	int c;
1085	int cnt, bare_lfs = 0;
1086	char buf[BUFSIZ];
1087
1088	transflag++;
1089	if (setjmp(urgcatch)) {
1090		transflag = 0;
1091		return (-1);
1092	}
1093	switch (type) {
1094
1095	case TYPE_I:
1096	case TYPE_L:
1097		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1098			if (write(fileno(outstr), buf, cnt) != cnt)
1099				goto file_err;
1100			byte_count += cnt;
1101		}
1102		if (cnt < 0)
1103			goto data_err;
1104		transflag = 0;
1105		return (0);
1106
1107	case TYPE_E:
1108		reply(553, "TYPE E not implemented.");
1109		transflag = 0;
1110		return (-1);
1111
1112	case TYPE_A:
1113		while ((c = getc(instr)) != EOF) {
1114			byte_count++;
1115			if (c == '\n')
1116				bare_lfs++;
1117			while (c == '\r') {
1118				if (ferror(outstr))
1119					goto data_err;
1120				if ((c = getc(instr)) != '\n') {
1121					(void) putc ('\r', outstr);
1122					if (c == '\0' || c == EOF)
1123						goto contin2;
1124				}
1125			}
1126			(void) putc(c, outstr);
1127	contin2:	;
1128		}
1129		fflush(outstr);
1130		if (ferror(instr))
1131			goto data_err;
1132		if (ferror(outstr))
1133			goto file_err;
1134		transflag = 0;
1135		if (bare_lfs) {
1136			lreply(226,
1137		"WARNING! %d bare linefeeds received in ASCII mode",
1138			    bare_lfs);
1139		(void)printf("   File may not have transferred correctly.\r\n");
1140		}
1141		return (0);
1142	default:
1143		reply(550, "Unimplemented TYPE %d in receive_data", type);
1144		transflag = 0;
1145		return (-1);
1146	}
1147
1148data_err:
1149	transflag = 0;
1150	perror_reply(426, "Data Connection");
1151	return (-1);
1152
1153file_err:
1154	transflag = 0;
1155	perror_reply(452, "Error writing file");
1156	return (-1);
1157}
1158
1159void
1160statfilecmd(filename)
1161	char *filename;
1162{
1163	FILE *fin;
1164	int c;
1165	char line[LINE_MAX];
1166
1167	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1168	fin = ftpd_popen(line, "r");
1169	lreply(211, "status of %s:", filename);
1170	while ((c = getc(fin)) != EOF) {
1171		if (c == '\n') {
1172			if (ferror(stdout)){
1173				perror_reply(421, "control connection");
1174				(void) ftpd_pclose(fin);
1175				dologout(1);
1176				/* NOTREACHED */
1177			}
1178			if (ferror(fin)) {
1179				perror_reply(551, filename);
1180				(void) ftpd_pclose(fin);
1181				return;
1182			}
1183			(void) putc('\r', stdout);
1184		}
1185		(void) putc(c, stdout);
1186	}
1187	(void) ftpd_pclose(fin);
1188	reply(211, "End of Status");
1189}
1190
1191void
1192statcmd()
1193{
1194	struct sockaddr_in *sin;
1195	u_char *a, *p;
1196
1197	lreply(211, "%s FTP server status:", hostname, version);
1198	printf("     %s\r\n", version);
1199	printf("     Connected to %s", remotehost);
1200	if (!isdigit(remotehost[0]))
1201		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1202	printf("\r\n");
1203	if (logged_in) {
1204		if (guest)
1205			printf("     Logged in anonymously\r\n");
1206		else
1207			printf("     Logged in as %s\r\n", pw->pw_name);
1208	} else if (askpasswd)
1209		printf("     Waiting for password\r\n");
1210	else
1211		printf("     Waiting for user name\r\n");
1212	printf("     TYPE: %s", typenames[type]);
1213	if (type == TYPE_A || type == TYPE_E)
1214		printf(", FORM: %s", formnames[form]);
1215	if (type == TYPE_L)
1216#if NBBY == 8
1217		printf(" %d", NBBY);
1218#else
1219		printf(" %d", bytesize);	/* need definition! */
1220#endif
1221	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1222	    strunames[stru], modenames[mode]);
1223	if (data != -1)
1224		printf("     Data connection open\r\n");
1225	else if (pdata != -1) {
1226		printf("     in Passive mode");
1227		sin = &pasv_addr;
1228		goto printaddr;
1229	} else if (usedefault == 0) {
1230		printf("     PORT");
1231		sin = &data_dest;
1232printaddr:
1233		a = (u_char *) &sin->sin_addr;
1234		p = (u_char *) &sin->sin_port;
1235#define UC(b) (((int) b) & 0xff)
1236		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1237			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1238#undef UC
1239	} else
1240		printf("     No data connection\r\n");
1241	reply(211, "End of status");
1242}
1243
1244void
1245fatal(s)
1246	char *s;
1247{
1248
1249	reply(451, "Error in server: %s\n", s);
1250	reply(221, "Closing connection due to server error.");
1251	dologout(0);
1252	/* NOTREACHED */
1253}
1254
1255void
1256#if __STDC__
1257reply(int n, const char *fmt, ...)
1258#else
1259reply(n, fmt, va_alist)
1260	int n;
1261	char *fmt;
1262        va_dcl
1263#endif
1264{
1265	va_list ap;
1266#if __STDC__
1267	va_start(ap, fmt);
1268#else
1269	va_start(ap);
1270#endif
1271	(void)printf("%d ", n);
1272	(void)vprintf(fmt, ap);
1273	(void)printf("\r\n");
1274	(void)fflush(stdout);
1275	if (debug) {
1276		syslog(LOG_DEBUG, "<--- %d ", n);
1277		vsyslog(LOG_DEBUG, fmt, ap);
1278	}
1279}
1280
1281void
1282#if __STDC__
1283lreply(int n, const char *fmt, ...)
1284#else
1285lreply(n, fmt, va_alist)
1286	int n;
1287	char *fmt;
1288        va_dcl
1289#endif
1290{
1291	va_list ap;
1292#if __STDC__
1293	va_start(ap, fmt);
1294#else
1295	va_start(ap);
1296#endif
1297	(void)printf("%d- ", n);
1298	(void)vprintf(fmt, ap);
1299	(void)printf("\r\n");
1300	(void)fflush(stdout);
1301	if (debug) {
1302		syslog(LOG_DEBUG, "<--- %d- ", n);
1303		vsyslog(LOG_DEBUG, fmt, ap);
1304	}
1305}
1306
1307static void
1308ack(s)
1309	char *s;
1310{
1311
1312	reply(250, "%s command successful.", s);
1313}
1314
1315void
1316nack(s)
1317	char *s;
1318{
1319
1320	reply(502, "%s command not implemented.", s);
1321}
1322
1323/* ARGSUSED */
1324void
1325yyerror(s)
1326	char *s;
1327{
1328	char *cp;
1329
1330	if (cp = strchr(cbuf,'\n'))
1331		*cp = '\0';
1332	reply(500, "'%s': command not understood.", cbuf);
1333}
1334
1335void
1336delete(name)
1337	char *name;
1338{
1339	struct stat st;
1340
1341	LOGCMD("delete", name);
1342	if (stat(name, &st) < 0) {
1343		perror_reply(550, name);
1344		return;
1345	}
1346	if ((st.st_mode&S_IFMT) == S_IFDIR) {
1347		if (rmdir(name) < 0) {
1348			perror_reply(550, name);
1349			return;
1350		}
1351		goto done;
1352	}
1353	if (unlink(name) < 0) {
1354		perror_reply(550, name);
1355		return;
1356	}
1357done:
1358	ack("DELE");
1359}
1360
1361void
1362cwd(path)
1363	char *path;
1364{
1365
1366	if (chdir(path) < 0)
1367		perror_reply(550, path);
1368	else
1369		ack("CWD");
1370}
1371
1372void
1373makedir(name)
1374	char *name;
1375{
1376
1377	LOGCMD("mkdir", name);
1378	if (mkdir(name, 0777) < 0)
1379		perror_reply(550, name);
1380	else
1381		reply(257, "MKD command successful.");
1382}
1383
1384void
1385removedir(name)
1386	char *name;
1387{
1388
1389	LOGCMD("rmdir", name);
1390	if (rmdir(name) < 0)
1391		perror_reply(550, name);
1392	else
1393		ack("RMD");
1394}
1395
1396void
1397pwd()
1398{
1399	char path[MAXPATHLEN + 1];
1400
1401	if (getwd(path) == (char *)NULL)
1402		reply(550, "%s.", path);
1403	else
1404		reply(257, "\"%s\" is current directory.", path);
1405}
1406
1407char *
1408renamefrom(name)
1409	char *name;
1410{
1411	struct stat st;
1412
1413	if (stat(name, &st) < 0) {
1414		perror_reply(550, name);
1415		return ((char *)0);
1416	}
1417	reply(350, "File exists, ready for destination name");
1418	return (name);
1419}
1420
1421void
1422renamecmd(from, to)
1423	char *from, *to;
1424{
1425
1426	LOGCMD2("rename", from, to);
1427	if (rename(from, to) < 0)
1428		perror_reply(550, "rename");
1429	else
1430		ack("RNTO");
1431}
1432
1433static void
1434dolog(sin)
1435	struct sockaddr_in *sin;
1436{
1437	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1438		sizeof(struct in_addr), AF_INET);
1439
1440	if (hp)
1441		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
1442	else
1443		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1444		    sizeof(remotehost));
1445#ifdef SETPROCTITLE
1446	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1447	setproctitle(proctitle);
1448#endif /* SETPROCTITLE */
1449
1450	if (logging)
1451		syslog(LOG_INFO, "connection from %s", remotehost);
1452}
1453
1454/*
1455 * Record logout in wtmp file
1456 * and exit with supplied status.
1457 */
1458void
1459dologout(status)
1460	int status;
1461{
1462
1463	if (logged_in) {
1464		(void) seteuid((uid_t)0);
1465		logwtmp(ttyline, "", "");
1466	}
1467	/* beware of flushing buffers after a SIGPIPE */
1468	_exit(status);
1469}
1470
1471static void
1472myoob(signo)
1473	int signo;
1474{
1475	char *cp;
1476
1477	/* only process if transfer occurring */
1478	if (!transflag)
1479		return;
1480	cp = tmpline;
1481	if (getline(cp, 7, stdin) == NULL) {
1482		reply(221, "You could at least say goodbye.");
1483		dologout(0);
1484	}
1485	upper(cp);
1486	if (strcmp(cp, "ABOR\r\n") == 0) {
1487		tmpline[0] = '\0';
1488		reply(426, "Transfer aborted. Data connection closed.");
1489		reply(226, "Abort successful");
1490		longjmp(urgcatch, 1);
1491	}
1492	if (strcmp(cp, "STAT\r\n") == 0) {
1493		if (file_size != (off_t) -1)
1494			reply(213, "Status: %qd of %qd bytes transferred",
1495			    byte_count, file_size);
1496		else
1497			reply(213, "Status: %qd bytes transferred", byte_count);
1498	}
1499}
1500
1501/*
1502 * Note: a response of 425 is not mentioned as a possible response to
1503 *	the PASV command in RFC959. However, it has been blessed as
1504 *	a legitimate response by Jon Postel in a telephone conversation
1505 *	with Rick Adams on 25 Jan 89.
1506 */
1507void
1508passive()
1509{
1510	int len;
1511	char *p, *a;
1512
1513	pdata = socket(AF_INET, SOCK_STREAM, 0);
1514	if (pdata < 0) {
1515		perror_reply(425, "Can't open passive connection");
1516		return;
1517	}
1518	pasv_addr = ctrl_addr;
1519	pasv_addr.sin_port = 0;
1520	(void) seteuid((uid_t)0);
1521	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1522		(void) seteuid((uid_t)pw->pw_uid);
1523		goto pasv_error;
1524	}
1525	(void) seteuid((uid_t)pw->pw_uid);
1526	len = sizeof(pasv_addr);
1527	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1528		goto pasv_error;
1529	if (listen(pdata, 1) < 0)
1530		goto pasv_error;
1531	a = (char *) &pasv_addr.sin_addr;
1532	p = (char *) &pasv_addr.sin_port;
1533
1534#define UC(b) (((int) b) & 0xff)
1535
1536	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1537		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1538	return;
1539
1540pasv_error:
1541	(void) close(pdata);
1542	pdata = -1;
1543	perror_reply(425, "Can't open passive connection");
1544	return;
1545}
1546
1547/*
1548 * Generate unique name for file with basename "local".
1549 * The file named "local" is already known to exist.
1550 * Generates failure reply on error.
1551 */
1552static char *
1553gunique(local)
1554	char *local;
1555{
1556	static char new[MAXPATHLEN];
1557	struct stat st;
1558	int count;
1559	char *cp;
1560
1561	cp = strrchr(local, '/');
1562	if (cp)
1563		*cp = '\0';
1564	if (stat(cp ? local : ".", &st) < 0) {
1565		perror_reply(553, cp ? local : ".");
1566		return ((char *) 0);
1567	}
1568	if (cp)
1569		*cp = '/';
1570	(void) strcpy(new, local);
1571	cp = new + strlen(new);
1572	*cp++ = '.';
1573	for (count = 1; count < 100; count++) {
1574		(void)sprintf(cp, "%d", count);
1575		if (stat(new, &st) < 0)
1576			return (new);
1577	}
1578	reply(452, "Unique file name cannot be created.");
1579	return (NULL);
1580}
1581
1582/*
1583 * Format and send reply containing system error number.
1584 */
1585void
1586perror_reply(code, string)
1587	int code;
1588	char *string;
1589{
1590
1591	reply(code, "%s: %s.", string, strerror(errno));
1592}
1593
1594static char *onefile[] = {
1595	"",
1596	0
1597};
1598
1599void
1600send_file_list(whichf)
1601	char *whichf;
1602{
1603	struct stat st;
1604	DIR *dirp = NULL;
1605	struct dirent *dir;
1606	FILE *dout = NULL;
1607	char **dirlist, *dirname;
1608	int simple = 0;
1609	int freeglob = 0;
1610	glob_t gl;
1611
1612	if (strpbrk(whichf, "~{[*?") != NULL) {
1613		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1614
1615		memset(&gl, 0, sizeof(gl));
1616		freeglob = 1;
1617		if (glob(whichf, flags, 0, &gl)) {
1618			reply(550, "not found");
1619			goto out;
1620		} else if (gl.gl_pathc == 0) {
1621			errno = ENOENT;
1622			perror_reply(550, whichf);
1623			goto out;
1624		}
1625		dirlist = gl.gl_pathv;
1626	} else {
1627		onefile[0] = whichf;
1628		dirlist = onefile;
1629		simple = 1;
1630	}
1631
1632	if (setjmp(urgcatch)) {
1633		transflag = 0;
1634		goto out;
1635	}
1636	while (dirname = *dirlist++) {
1637		if (stat(dirname, &st) < 0) {
1638			/*
1639			 * If user typed "ls -l", etc, and the client
1640			 * used NLST, do what the user meant.
1641			 */
1642			if (dirname[0] == '-' && *dirlist == NULL &&
1643			    transflag == 0) {
1644				retrieve("/bin/ls %s", dirname);
1645				goto out;
1646			}
1647			perror_reply(550, whichf);
1648			if (dout != NULL) {
1649				(void) fclose(dout);
1650				transflag = 0;
1651				data = -1;
1652				pdata = -1;
1653			}
1654			goto out;
1655		}
1656
1657		if (S_ISREG(st.st_mode)) {
1658			if (dout == NULL) {
1659				dout = dataconn("file list", (off_t)-1, "w");
1660				if (dout == NULL)
1661					goto out;
1662				transflag++;
1663			}
1664			fprintf(dout, "%s%s\n", dirname,
1665				type == TYPE_A ? "\r" : "");
1666			byte_count += strlen(dirname) + 1;
1667			continue;
1668		} else if (!S_ISDIR(st.st_mode))
1669			continue;
1670
1671		if ((dirp = opendir(dirname)) == NULL)
1672			continue;
1673
1674		while ((dir = readdir(dirp)) != NULL) {
1675			char nbuf[MAXPATHLEN];
1676
1677			if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1678				continue;
1679			if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1680			    dir->d_namlen == 2)
1681				continue;
1682
1683			sprintf(nbuf, "%s/%s", dirname, dir->d_name);
1684
1685			/*
1686			 * We have to do a stat to insure it's
1687			 * not a directory or special file.
1688			 */
1689			if (simple || (stat(nbuf, &st) == 0 &&
1690			    S_ISREG(st.st_mode))) {
1691				if (dout == NULL) {
1692					dout = dataconn("file list", (off_t)-1,
1693						"w");
1694					if (dout == NULL)
1695						goto out;
1696					transflag++;
1697				}
1698				if (nbuf[0] == '.' && nbuf[1] == '/')
1699					fprintf(dout, "%s%s\n", &nbuf[2],
1700						type == TYPE_A ? "\r" : "");
1701				else
1702					fprintf(dout, "%s%s\n", nbuf,
1703						type == TYPE_A ? "\r" : "");
1704				byte_count += strlen(nbuf) + 1;
1705			}
1706		}
1707		(void) closedir(dirp);
1708	}
1709
1710	if (dout == NULL)
1711		reply(550, "No files found.");
1712	else if (ferror(dout) != 0)
1713		perror_reply(550, "Data connection");
1714	else
1715		reply(226, "Transfer complete.");
1716
1717	transflag = 0;
1718	if (dout != NULL)
1719		(void) fclose(dout);
1720	data = -1;
1721	pdata = -1;
1722out:
1723	if (freeglob) {
1724		freeglob = 0;
1725		globfree(&gl);
1726	}
1727}
1728
1729#ifdef SETPROCTITLE
1730/*
1731 * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
1732 * Warning, since this is usually started from inetd.conf, it often doesn't
1733 * have much of an environment or arglist to overwrite.
1734 */
1735void
1736#if __STDC__
1737setproctitle(const char *fmt, ...)
1738#else
1739setproctitle(fmt, va_alist)
1740	char *fmt;
1741        va_dcl
1742#endif
1743{
1744	int i;
1745	va_list ap;
1746	char *p, *bp, ch;
1747	char buf[LINE_MAX];
1748
1749#if __STDC__
1750	va_start(ap, fmt);
1751#else
1752	va_start(ap);
1753#endif
1754	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
1755
1756	/* make ps print our process name */
1757	p = Argv[0];
1758	*p++ = '-';
1759
1760	i = strlen(buf);
1761	if (i > LastArgv - p - 2) {
1762		i = LastArgv - p - 2;
1763		buf[i] = '\0';
1764	}
1765	bp = buf;
1766	while (ch = *bp++)
1767		if (ch != '\n' && ch != '\r')
1768			*p++ = ch;
1769	while (p < LastArgv)
1770		*p++ = ' ';
1771}
1772#endif /* SETPROCTITLE */
1773
1774#ifdef STATS
1775logxfer(name, size, start)
1776	char *name;
1777	long size;
1778	long start;
1779{
1780	char buf[1024];
1781	char path[MAXPATHLEN + 1];
1782	long now;
1783
1784	if (statfd >= 0 && getwd(path) != NULL) {
1785		time(&now);
1786		sprintf(buf, "%.20s!%s!%s!%s/%s!%ld!%ld\n",
1787			ctime(&now)+4, ident, remotehost,
1788			path, name, size, now - start + (now == start));
1789		write(statfd, buf, strlen(buf));
1790	}
1791}
1792
1793char *
1794copy(s)
1795	char *s;
1796{
1797	char *p;
1798
1799	p = malloc((unsigned) strlen(s) + 1);
1800	if (p == NULL)
1801		fatal("Ran out of memory.");
1802	(void) strcpy(p, s);
1803	return (p);
1804}
1805#endif
1806