while ((ch = getopt(argc, argv, "dlt:T:u:Uv")) != EOF) {
while ((ch = getopt(argc, argv, argstr)) != EOF) {
static char	*gunique __P((char *));static void	 lostconn __P((int));static int	 receive_data __P((FILE *, FILE *));static void	 send_data __P((FILE *, FILE *, off_t, off_t, int));static struct passwd *		 sgetpwnam __P((char *));static char	*sgetsave __P((char *));static char *curdir(){	static char path[MAXPATHLEN+1+1];	/* path + '/' + '\0' */	if (getcwd(path, sizeof(path)-2) == NULL)		return ("");	if (path[1] != '\0')		/* special case for root dir. */		strcat(path, "/");	/* For guest account, skip / since it's chrooted */	return (guest ? path+1 : path);}intmain(argc, argv, envp)	int argc;	char *argv[];	char **envp;{	int addrlen, ch, on = 1, tos;	char *cp, line[LINE_MAX];	FILE *fd;	/*	 * LOG_NDELAY sets up the logging connection immediately,	 * necessary for anonymous ftp's that chroot and can't do it later.	 */	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);	addrlen = sizeof(his_addr);	if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {		syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);		exit(1);	}	addrlen = sizeof(ctrl_addr);	if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {		syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);		exit(1);	}#ifdef IP_TOS	tos = IPTOS_LOWDELAY;	if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");#endif	data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);	debug = 0;	/* set this here so klogin can use it... */	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());	while ((ch = getopt(argc, argv, "dlt:T:u:Uv")) != EOF) {		switch (ch) {		case 'd':			debug = 1;			break;		case 'l':			logging++;	/* > 1 == extra logging */			break;		case 't':			timeout = atoi(optarg);			if (maxtimeout < timeout)				maxtimeout = timeout;			break;		case 'T':			maxtimeout = atoi(optarg);			if (timeout > maxtimeout)				timeout = maxtimeout;			break;		case 'u':		    {			long val = 0;			val = strtol(optarg, &optarg, 8);			if (*optarg != '\0' || val < 0)				warnx("bad value for -u");			else				defumask = val;			break;		    }		case 'U':			doutmp = 1;			break;		case 'v':			debug = 1;			break;		default:			warnx("unknown flag -%c ignored", optopt);			break;		}	}	(void) freopen(_PATH_DEVNULL, "w", stderr);	(void) signal(SIGPIPE, lostconn);	(void) signal(SIGCHLD, SIG_IGN);	if ((long)signal(SIGURG, myoob) < 0)		syslog(LOG_ERR, "signal: %m");	/* Try to handle urgent data inline */#ifdef SO_OOBINLINE	if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)		syslog(LOG_ERR, "setsockopt: %m");#endif#ifdef	F_SETOWN	if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)		syslog(LOG_ERR, "fcntl F_SETOWN: %m");#endif	dolog(&his_addr);	/*	 * Set up default state	 */	data = -1;	type = TYPE_A;	form = FORM_N;	stru = STRU_F;	mode = MODE_S;	tmpline[0] = '\0';	/* If logins are disabled, print out the message. */	if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {		while (fgets(line, sizeof(line), fd) != NULL) {			if ((cp = strchr(line, '\n')) != NULL)				*cp = '\0';			lreply(530, "%s", line);		}		(void) fflush(stdout);		(void) fclose(fd);		reply(530, "System not available.");		exit(0);	}	if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {		while (fgets(line, sizeof(line), fd) != NULL) {			if ((cp = strchr(line, '\n')) != NULL)				*cp = '\0';			lreply(220, "%s", line);		}		(void) fflush(stdout);		(void) fclose(fd);		/* reply(220,) must follow */	}	(void) gethostname(hostname, sizeof(hostname));	reply(220, "%s FTP server (%s) ready.", hostname, version);	(void) setjmp(errcatch);	for (;;)		(void) yyparse();	/* NOTREACHED */}static voidlostconn(signo)	int signo;{	if (debug)		syslog(LOG_DEBUG, "lost connection");	dologout(-1);}/* * Helper function for sgetpwnam(). */static char *sgetsave(s)	char *s;{	char *new = malloc((unsigned) strlen(s) + 1);	if (new == NULL) {		perror_reply(421, "Local resource failure: malloc");		dologout(1);		/* NOTREACHED */	}	(void) strcpy(new, s);	return (new);}/* * Save the result of a getpwnam.  Used for USER command, since * the data returned must not be clobbered by any other command * (e.g., globbing). */static struct passwd *sgetpwnam(name)	char *name;{	static struct passwd save;	struct passwd *p;	if ((p = getpwnam(name)) == NULL)		return (p);	if (save.pw_name) {		free(save.pw_name);		free(save.pw_passwd);		free(save.pw_gecos);		free(save.pw_dir);		free(save.pw_shell);	}	save = *p;	save.pw_name = sgetsave(p->pw_name);	save.pw_passwd = sgetsave(p->pw_passwd);	save.pw_gecos = sgetsave(p->pw_gecos);	save.pw_dir = sgetsave(p->pw_dir);	save.pw_shell = sgetsave(p->pw_shell);	return (&save);}static int login_attempts;	/* number of failed login attempts */static int askpasswd;		/* had user command, ask for passwd */static char curname[10];	/* current USER name *//* * USER command. * Sets global passwd pointer pw if named account exists and is acceptable; * sets askpasswd if a PASS command is expected.  If logged in previously, * need to reset state.  If name is "ftp" or "anonymous", the name is not in * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. * If account doesn't exist, ask for passwd anyway.  Otherwise, check user * requesting login privileges.  Disallow anyone who does not have a standard * shell as returned by getusershell().  Disallow anyone mentioned in the file * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. */voiduser(name)	char *name;{	char *cp, *shell;	if (logged_in) {		if (guest) {			reply(530, "Can't change user from guest login.");			return;		} else if (dochroot) {			reply(530, "Can't change user from chroot user.");			return;		}		end_login();	}	guest = 0;	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {		if (checkuser(_PATH_FTPUSERS, "ftp") ||		    checkuser(_PATH_FTPUSERS, "anonymous"))			reply(530, "User %s access denied.", name);		else if ((pw = sgetpwnam("ftp")) != NULL) {			guest = 1;			askpasswd = 1;			reply(331,			    "Guest login ok, type your name as password.");		} else			reply(530, "User %s unknown.", name);		if (!askpasswd && logging)			syslog(LOG_NOTICE,			    "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);		return;	}	if (pw = sgetpwnam(name)) {		if ((shell = pw->pw_shell) == NULL || *shell == 0)			shell = _PATH_BSHELL;		while ((cp = getusershell()) != NULL)			if (strcmp(cp, shell) == 0)				break;		endusershell();		if (cp == NULL || checkuser(_PATH_FTPUSERS, name)) {			reply(530, "User %s access denied.", name);			if (logging)				syslog(LOG_NOTICE,				    "FTP LOGIN REFUSED FROM %s, %s",				    remotehost, name);			pw = (struct passwd *) NULL;			return;		}	}	if (logging)		strncpy(curname, name, sizeof(curname)-1);#ifdef SKEY	if (!skey_haskey(name)) {		char *myskey, *skey_keyinfo __P((char *name));		myskey = skey_keyinfo(name);		reply(331, "Password [%s] for %s required.",		    myskey ? myskey : "error getting challenge", name);	} else#endif		reply(331, "Password required for %s.", name);	askpasswd = 1;	/*	 * Delay before reading passwd after first failed	 * attempt to slow down passwd-guessing programs.	 */	if (login_attempts)		sleep((unsigned) login_attempts);}/* * Check if a user is in the file "fname" */static intcheckuser(fname, name)	char *fname;	char *name;{	FILE *fd;	int found = 0;	char *p, line[BUFSIZ];	if ((fd = fopen(fname, "r")) != NULL) {		while (fgets(line, sizeof(line), fd) != NULL)			if ((p = strchr(line, '\n')) != NULL) {				*p = '\0';				if (line[0] == '#')					continue;				if (strcmp(line, name) == 0) {					found = 1;					break;				}			}		(void) fclose(fd);	}	return (found);}/* * Terminate login as previous user, if any, resetting state; * used when USER command is given or login fails. */static voidend_login(){	(void) seteuid((uid_t)0);	if (logged_in) {		logwtmp(ttyline, "", "");		if (doutmp)			logout(utmp.ut_line);	}	pw = NULL;	logged_in = 0;	guest = 0;	dochroot = 0;}voidpass(passwd)	char *passwd;{	int rval;	FILE *fd;	if (logged_in || askpasswd == 0) {		reply(503, "Login with USER first.");		return;	}	askpasswd = 0;	if (!guest) {		/* "ftp" is only account allowed no password */		if (pw == NULL) {			rval = 1;	/* failure below */			goto skip;		}#if defined(KERBEROS)		rval = klogin(pw, "", hostname, passwd);		if (rval == 0)			goto skip;#endif#ifdef SKEY		if (skey_haskey(pw->pw_name) == 0 &&		   (skey_passcheck(pw->pw_name, passwd) != -1)) {			rval = 0;			goto skip;		}#endif		/* the strcmp does not catch null passwords! */		if (pw == NULL || *pw->pw_passwd == '\0' ||		    strcmp(crypt(passwd, (pw ? pw->pw_passwd : "xx")), pw->pw_passwd)) {			rval = 1;	 /* failure */			goto skip;		}		rval = 0;skip:		/*		 * If rval == 1, the user failed the authentication check		 * above.  If rval == 0, either Kerberos or local authentication		 * succeeded.		 */		if (rval) {			reply(530, "Login incorrect.");			if (logging)				syslog(LOG_NOTICE,				    "FTP LOGIN FAILED FROM %s, %s",				    remotehost, curname);			pw = NULL;			if (login_attempts++ >= 5) {				syslog(LOG_NOTICE,				    "repeated login failures from %s",				    remotehost);				exit(0);			}			return;		}	}	login_attempts = 0;		/* this time successful */	if (setegid((gid_t)pw->pw_gid) < 0) {		reply(550, "Can't set gid.");		return;	}	(void) initgroups(pw->pw_name, pw->pw_gid);	/* open wtmp before chroot */	logwtmp(ttyline, pw->pw_name, remotehost);	/* open utmp before chroot */	if (doutmp) {		memset((void *)&utmp, 0, sizeof(utmp));		(void)time(&utmp.ut_time);		(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));		(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));		(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));		login(&utmp);	}	logged_in = 1;	dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);	if (guest) {		/*		 * We MUST do a chdir() after the chroot. Otherwise		 * the old current directory will be accessible as "."		 * outside the new root!		 */		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {			reply(550, "Can't set guest privileges.");			goto bad;		}	} else if (dochroot) {		if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {			reply(550, "Can't change root.");			goto bad;		}	} else if (chdir(pw->pw_dir) < 0) {		if (chdir("/") < 0) {			reply(530, "User %s: can't change directory to %s.",			    pw->pw_name, pw->pw_dir);			goto bad;		} else			lreply(230, "No directory! Logging in with home=/");	}	if (seteuid((uid_t)pw->pw_uid) < 0) {		reply(550, "Can't set uid.");		goto bad;	}	/*	 * Display a login message, if it exists.	 * N.B. reply(230,) must follow the message.	 */	if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {		char *cp, line[LINE_MAX];		while (fgets(line, sizeof(line), fd) != NULL) {			if ((cp = strchr(line, '\n')) != NULL)				*cp = '\0';			lreply(230, "%s", line);		}		(void) fflush(stdout);		(void) fclose(fd);	}	if (guest) {		reply(230, "Guest login ok, access restrictions apply.");#ifdef HASSETPROCTITLE		snprintf(proctitle, sizeof(proctitle),		    "%s: anonymous/%.*s", remotehost,		    sizeof(proctitle) - sizeof(remotehost) -		    sizeof(": anonymous/"), passwd);		setproctitle(proctitle);#endif /* HASSETPROCTITLE */		if (logging)			syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",			    remotehost, passwd);	} else {		reply(230, "User %s logged in.", pw->pw_name);#ifdef HASSETPROCTITLE		snprintf(proctitle, sizeof(proctitle),		    "%s: %s", remotehost, pw->pw_name);		setproctitle(proctitle);#endif /* HASSETPROCTITLE */		if (logging)			syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",			    remotehost, pw->pw_name);	}	(void) umask(defumask);	return;bad:	/* Forget all about it... */	end_login();}voidretrieve(cmd, name)	char *cmd, *name;{	FILE *fin, *dout;	struct stat st;	int (*closefunc) __P((FILE *));	if (cmd == 0) {		fin = fopen(name, "r"), closefunc = fclose;		st.st_size = 0;	} else {		char line[BUFSIZ];		(void) sprintf(line, cmd, name), name = line;		fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose;		st.st_size = -1;		st.st_blksize = BUFSIZ;	}	if (fin == NULL) {		if (errno != 0) {			perror_reply(550, name);			if (cmd == 0) {				LOGCMD("get", name);			}		}		return;	}	byte_count = -1;	if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {		reply(550, "%s: not a plain file.", name);		goto done;	}	if (restart_point) {		if (type == TYPE_A) {			off_t i, n;			int c;			n = restart_point;			i = 0;			while (i++ < n) {				if ((c=getc(fin)) == EOF) {					perror_reply(550, name);					goto done;				}				if (c == '\n')					i++;			}		} else if (lseek(fileno(fin), restart_point, L_SET) < 0) {			perror_reply(550, name);			goto done;		}	}	dout = dataconn(name, st.st_size, "w");	if (dout == NULL)		goto done;	send_data(fin, dout, st.st_blksize, st.st_size,		  (restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)));	(void) fclose(dout);	data = -1;	pdata = -1;done:	if (cmd == 0)		LOGBYTES("get", name, byte_count);	(*closefunc)(fin);}voidstore(name, mode, unique)	char *name, *mode;	int unique;{	FILE *fout, *din;	struct stat st;	int (*closefunc) __P((FILE *));	if (unique && stat(name, &st) == 0 &&	    (name = gunique(name)) == NULL) {		LOGCMD(*mode == 'w' ? "put" : "append", name);		return;	}	if (restart_point)		mode = "r+";	fout = fopen(name, mode);	closefunc = fclose;	if (fout == NULL) {		perror_reply(553, name);		LOGCMD(*mode == 'w' ? "put" : "append", name);		return;	}	byte_count = -1;	if (restart_point) {		if (type == TYPE_A) {			off_t i, n;			int c;			n = restart_point;			i = 0;			while (i++ < n) {				if ((c=getc(fout)) == EOF) {					perror_reply(550, name);					goto done;				}				if (c == '\n')					i++;			}			/*			 * We must do this seek to "current" position			 * because we are changing from reading to			 * writing.			 */			if (fseek(fout, 0L, L_INCR) < 0) {				perror_reply(550, name);				goto done;			}		} else if (lseek(fileno(fout), restart_point, L_SET) < 0) {			perror_reply(550, name);			goto done;		}	}	din = dataconn(name, (off_t)-1, "r");	if (din == NULL)		goto done;	if (receive_data(din, fout) == 0) {		if (unique)			reply(226, "Transfer complete (unique file name:%s).",			    name);		else			reply(226, "Transfer complete.");	}	(void) fclose(din);	data = -1;	pdata = -1;done:	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);	(*closefunc)(fout);}static FILE *getdatasock(mode)	char *mode;{	int on = 1, s, t, tries;	if (data >= 0)		return (fdopen(data, mode));	(void) seteuid((uid_t)0);	s = socket(AF_INET, SOCK_STREAM, 0);	if (s < 0)		goto bad;	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,	    (char *) &on, sizeof(on)) < 0)		goto bad;	/* anchor socket to avoid multi-homing problems */	data_source.sin_len = sizeof(struct sockaddr_in);	data_source.sin_family = AF_INET;	data_source.sin_addr = ctrl_addr.sin_addr;	for (tries = 1; ; tries++) {		if (bind(s, (struct sockaddr *)&data_source,		    sizeof(data_source)) >= 0)			break;		if (errno != EADDRINUSE || tries > 10)			goto bad;		sleep(tries);	}	(void) seteuid((uid_t)pw->pw_uid);#ifdef IP_TOS	on = IPTOS_THROUGHPUT;	if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)		syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");#endif	return (fdopen(s, mode));bad:	/* Return the real value of errno (close may change it) */	t = errno;	(void) seteuid((uid_t)pw->pw_uid);	(void) close(s);	errno = t;	return (NULL);}static FILE *dataconn(name, size, mode)	char *name;	off_t size;	char *mode;{	char sizebuf[32];	FILE *file;	int retry = 0, tos;	file_size = size;	byte_count = 0;	if (size != (off_t) -1)		(void) sprintf(sizebuf, " (%qd bytes)", size);	else		(void) strcpy(sizebuf, "");	if (pdata >= 0) {		struct sockaddr_in from;		int s, fromlen = sizeof(from);		s = accept(pdata, (struct sockaddr *)&from, &fromlen);		if (s < 0) {			reply(425, "Can't open data connection.");			(void) close(pdata);			pdata = -1;			return (NULL);		}		if (ntohs(from.sin_port) < IPPORT_RESERVED) {			perror_reply(425, "Can't build data connection");			(void) close(pdata);			(void) close(s);			pdata = -1;			return (NULL);		}		if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) {			perror_reply(435, "Can't build data connection"); 			(void) close(pdata);			(void) close(s);			pdata = -1;			return (NULL);		}		(void) close(pdata);		pdata = s;#ifdef IP_TOS		tos = IPTOS_THROUGHPUT;		(void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,		    sizeof(int));#endif		reply(150, "Opening %s mode data connection for '%s'%s.",		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);		return (fdopen(pdata, mode));	}	if (data >= 0) {		reply(125, "Using existing data connection for '%s'%s.",		    name, sizebuf);		usedefault = 1;		return (fdopen(data, mode));	}	if (usedefault)		data_dest = his_addr;	usedefault = 1;	file = getdatasock(mode);	if (file == NULL) {		reply(425, "Can't create data socket (%s,%d): %s.",		    inet_ntoa(data_source.sin_addr),		    ntohs(data_source.sin_port), strerror(errno));		return (NULL);	}	data = fileno(file);	/*	 * attempt to connect to reserved port on client machine;	 * this looks like an attack	 */	if (ntohs(data_dest.sin_port) < IPPORT_RESERVED) {		perror_reply(425, "Can't build data connection");		(void) fclose(file);		data = -1;		return NULL;	}	if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) {		perror_reply(435, "Can't build data connection");		(void) fclose(file);		data = -1;		return NULL;	}	while (connect(data, (struct sockaddr *)&data_dest,	    sizeof(data_dest)) < 0) {		if (errno == EADDRINUSE && retry < swaitmax) {			sleep((unsigned) swaitint);			retry += swaitint;			continue;		}		perror_reply(425, "Can't build data connection");		(void) fclose(file);		data = -1;		return (NULL);	}	reply(150, "Opening %s mode data connection for '%s'%s.",	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);	return (file);}/* * Tranfer the contents of "instr" to "outstr" peer using the appropriate * encapsulation of the data subject to Mode, Structure, and Type. * * NB: Form isn't handled. */static voidsend_data(instr, outstr, blksize, filesize, isreg)	FILE *instr, *outstr;	off_t blksize;	off_t filesize;	int isreg;{	int c, cnt, filefd, netfd;	char *buf, *bp;	size_t len;	transflag++;	if (setjmp(urgcatch)) {		transflag = 0;		return;	}	switch (type) {	case TYPE_A:		while ((c = getc(instr)) != EOF) {			byte_count++;			if (c == '\n') {				if (ferror(outstr))					goto data_err;				(void) putc('\r', outstr);			}			(void) putc(c, outstr);		}		fflush(outstr);		transflag = 0;		if (ferror(instr))			goto file_err;		if (ferror(outstr))			goto data_err;		reply(226, "Transfer complete.");		return;	case TYPE_I:	case TYPE_L:		/*		 * isreg is only set if we are not doing restart and we		 * are sending a regular file		 */		netfd = fileno(outstr);		filefd = fileno(instr);		if (isreg && filesize < (off_t)16 * 1024 * 1024) {			buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd,				   (off_t)0);			if (!buf) {				syslog(LOG_WARNING, "mmap(%lu): %m",				       (unsigned long)filesize);				goto oldway;			}			bp = buf;			len = filesize;			do {				cnt = write(netfd, bp, len);				len -= cnt;				bp += cnt;				if (cnt > 0) byte_count += cnt;			} while(cnt > 0 && len > 0);			transflag = 0;			munmap(buf, (size_t)filesize);			if (cnt < 0)				goto data_err;			reply(226, "Transfer complete.");			return;		}oldway:		if ((buf = malloc((u_int)blksize)) == NULL) {			transflag = 0;			perror_reply(451, "Local resource failure: malloc");			return;		}		while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&		    write(netfd, buf, cnt) == cnt)			byte_count += cnt;		transflag = 0;		(void)free(buf);		if (cnt != 0) {			if (cnt < 0)				goto file_err;			goto data_err;		}		reply(226, "Transfer complete.");		return;	default:		transflag = 0;		reply(550, "Unimplemented TYPE %d in send_data", type);		return;	}data_err:	transflag = 0;	perror_reply(426, "Data connection");	return;file_err:	transflag = 0;	perror_reply(551, "Error on input file");}/* * Transfer data from peer to "outstr" using the appropriate encapulation of * the data subject to Mode, Structure, and Type. * * N.B.: Form isn't handled. */static intreceive_data(instr, outstr)	FILE *instr, *outstr;{	int c;	int cnt, bare_lfs = 0;	char buf[BUFSIZ];	transflag++;	if (setjmp(urgcatch)) {		transflag = 0;		return (-1);	}	switch (type) {	case TYPE_I:	case TYPE_L:		while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {			if (write(fileno(outstr), buf, cnt) != cnt)				goto file_err;			byte_count += cnt;		}		if (cnt < 0)			goto data_err;		transflag = 0;		return (0);	case TYPE_E:		reply(553, "TYPE E not implemented.");		transflag = 0;		return (-1);	case TYPE_A:		while ((c = getc(instr)) != EOF) {			byte_count++;			if (c == '\n')				bare_lfs++;			while (c == '\r') {				if (ferror(outstr))					goto data_err;				if ((c = getc(instr)) != '\n') {					(void) putc ('\r', outstr);					if (c == '\0' || c == EOF)						goto contin2;				}			}			(void) putc(c, outstr);	contin2:	;		}		fflush(outstr);		if (ferror(instr))			goto data_err;		if (ferror(outstr))			goto file_err;		transflag = 0;		if (bare_lfs) {			lreply(226,		"WARNING! %d bare linefeeds received in ASCII mode",			    bare_lfs);		(void)printf("   File may not have transferred correctly.\r\n");		}		return (0);	default:		reply(550, "Unimplemented TYPE %d in receive_data", type);		transflag = 0;		return (-1);	}data_err:	transflag = 0;	perror_reply(426, "Data Connection");	return (-1);file_err:	transflag = 0;	perror_reply(452, "Error writing file");	return (-1);}voidstatfilecmd(filename)	char *filename;{	FILE *fin;	int c;	char line[LINE_MAX];	(void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);	fin = ftpd_popen(line, "r");	lreply(211, "status of %s:", filename);	while ((c = getc(fin)) != EOF) {		if (c == '\n') {			if (ferror(stdout)){				perror_reply(421, "control connection");				(void) ftpd_pclose(fin);				dologout(1);				/* NOTREACHED */			}			if (ferror(fin)) {				perror_reply(551, filename);				(void) ftpd_pclose(fin);				return;			}			(void) putc('\r', stdout);		}		(void) putc(c, stdout);	}	(void) ftpd_pclose(fin);	reply(211, "End of Status");}voidstatcmd(){	struct sockaddr_in *sin;	u_char *a, *p;	lreply(211, "%s FTP server status:", hostname, version);	printf("     %s\r\n", version);	printf("     Connected to %s", remotehost);	if (!isdigit(remotehost[0]))		printf(" (%s)", inet_ntoa(his_addr.sin_addr));	printf("\r\n");	if (logged_in) {		if (guest)			printf("     Logged in anonymously\r\n");		else			printf("     Logged in as %s\r\n", pw->pw_name);	} else if (askpasswd)		printf("     Waiting for password\r\n");	else		printf("     Waiting for user name\r\n");	printf("     TYPE: %s", typenames[type]);	if (type == TYPE_A || type == TYPE_E)		printf(", FORM: %s", formnames[form]);	if (type == TYPE_L)#if NBBY == 8		printf(" %d", NBBY);#else		printf(" %d", bytesize);	/* need definition! */#endif	printf("; STRUcture: %s; transfer MODE: %s\r\n",	    strunames[stru], modenames[mode]);	if (data != -1)		printf("     Data connection open\r\n");	else if (pdata != -1) {		printf("     in Passive mode");		sin = &pasv_addr;		goto printaddr;	} else if (usedefault == 0) {		printf("     PORT");		sin = &data_dest;printaddr:		a = (u_char *) &sin->sin_addr;		p = (u_char *) &sin->sin_port;#define UC(b) (((int) b) & 0xff)		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));#undef UC	} else		printf("     No data connection\r\n");	reply(211, "End of status");}voidfatal(s)	char *s;{	reply(451, "Error in server: %s\n", s);	reply(221, "Closing connection due to server error.");	dologout(0);	/* NOTREACHED */}void#if __STDC__reply(int n, const char *fmt, ...)#elsereply(n, fmt, va_alist)	int n;	char *fmt;        va_dcl#endif{	va_list ap;#if __STDC__	va_start(ap, fmt);#else	va_start(ap);#endif	(void)printf("%d ", n);	(void)vprintf(fmt, ap);	(void)printf("\r\n");	(void)fflush(stdout);	if (debug) {		syslog(LOG_DEBUG, "<--- %d ", n);		vsyslog(LOG_DEBUG, fmt, ap);	}}void#if __STDC__lreply(int n, const char *fmt, ...)#elselreply(n, fmt, va_alist)	int n;	char *fmt;        va_dcl#endif{	va_list ap;#if __STDC__	va_start(ap, fmt);#else	va_start(ap);#endif	(void)printf("%d- ", n);	(void)vprintf(fmt, ap);	(void)printf("\r\n");	(void)fflush(stdout);	if (debug) {		syslog(LOG_DEBUG, "<--- %d- ", n);		vsyslog(LOG_DEBUG, fmt, ap);	}}static voidack(s)	char *s;{	reply(250, "%s command successful.", s);}voidnack(s)	char *s;{	reply(502, "%s command not implemented.", s);}/* ARGSUSED */voidyyerror(s)	char *s;{	char *cp;	if (cp = strchr(cbuf,'\n'))		*cp = '\0';	reply(500, "'%s': command not understood.", cbuf);}voiddelete(name)	char *name;{	struct stat st;	LOGCMD("delete", name);	if (stat(name, &st) < 0) {		perror_reply(550, name);		return;	}	if ((st.st_mode&S_IFMT) == S_IFDIR) {		if (rmdir(name) < 0) {			perror_reply(550, name);			return;		}		goto done;	}	if (unlink(name) < 0) {		perror_reply(550, name);		return;	}done:	ack("DELE");}voidcwd(path)	char *path;{	if (chdir(path) < 0)		perror_reply(550, path);	else		ack("CWD");}voidmakedir(name)	char *name;{	LOGCMD("mkdir", name);	if (mkdir(name, 0777) < 0)		perror_reply(550, name);	else		reply(257, "MKD command successful.");}voidremovedir(name)	char *name;{	LOGCMD("rmdir", name);	if (rmdir(name) < 0)		perror_reply(550, name);	else		ack("RMD");}voidpwd(){	char path[MAXPATHLEN + 1];	if (getwd(path) == (char *)NULL)		reply(550, "%s.", path);	else		reply(257, "\"%s\" is current directory.", path);}char *renamefrom(name)	char *name;{	struct stat st;	if (stat(name, &st) < 0) {		perror_reply(550, name);		return ((char *)0);	}	reply(350, "File exists, ready for destination name");	return (name);}voidrenamecmd(from, to)	char *from, *to;{	LOGCMD2("rename", from, to);	if (rename(from, to) < 0)		perror_reply(550, "rename");	else		ack("RNTO");}static voiddolog(sin)	struct sockaddr_in *sin;{	struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,		sizeof(struct in_addr), AF_INET);	if (hp)		(void) strncpy(remotehost, hp->h_name, sizeof(remotehost));	else		(void) strncpy(remotehost, inet_ntoa(sin->sin_addr),		    sizeof(remotehost));#ifdef HASSETPROCTITLE	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);	setproctitle(proctitle);#endif /* HASSETPROCTITLE */	if (logging)		syslog(LOG_INFO, "connection from %s", remotehost);}/* * Record logout in wtmp file * and exit with supplied status. */voiddologout(status)	int status;{	if (logged_in) {		(void) seteuid((uid_t)0);		logwtmp(ttyline, "", "");		if (doutmp)			logout(utmp.ut_line);#if defined(KERBEROS)		if (!notickets && krbtkfile_env)			unlink(krbtkfile_env);#endif	}	/* beware of flushing buffers after a SIGPIPE */	_exit(status);}static voidmyoob(signo)	int signo;{	char *cp;	/* only process if transfer occurring */	if (!transflag)		return;	cp = tmpline;	if (getline(cp, 7, stdin) == NULL) {		reply(221, "You could at least say goodbye.");		dologout(0);	}	upper(cp);	if (strcmp(cp, "ABOR\r\n") == 0) {		tmpline[0] = '\0';		reply(426, "Transfer aborted. Data connection closed.");		reply(226, "Abort successful");		longjmp(urgcatch, 1);	}	if (strcmp(cp, "STAT\r\n") == 0) {		if (file_size != (off_t) -1)			reply(213, "Status: %qd of %qd bytes transferred",			    byte_count, file_size);		else			reply(213, "Status: %qd bytes transferred", byte_count);	}}/* * Note: a response of 425 is not mentioned as a possible response to *	the PASV command in RFC959. However, it has been blessed as *	a legitimate response by Jon Postel in a telephone conversation *	with Rick Adams on 25 Jan 89. */voidpassive(){	int len;	char *p, *a;	pdata = socket(AF_INET, SOCK_STREAM, 0);	if (pdata < 0) {		perror_reply(425, "Can't open passive connection");		return;	}	pasv_addr = ctrl_addr;	pasv_addr.sin_port = 0;	(void) seteuid((uid_t)0);	if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {		(void) seteuid((uid_t)pw->pw_uid);		goto pasv_error;	}	(void) seteuid((uid_t)pw->pw_uid);	len = sizeof(pasv_addr);	if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)		goto pasv_error;	if (listen(pdata, 1) < 0)		goto pasv_error;	a = (char *) &pasv_addr.sin_addr;	p = (char *) &pasv_addr.sin_port;#define UC(b) (((int) b) & 0xff)	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));	return;pasv_error:	(void) close(pdata);	pdata = -1;	perror_reply(425, "Can't open passive connection");	return;}/* * Generate unique name for file with basename "local". * The file named "local" is already known to exist. * Generates failure reply on error. */static char *gunique(local)	char *local;{	static char new[MAXPATHLEN];	struct stat st;	int count;	char *cp;	cp = strrchr(local, '/');	if (cp)		*cp = '\0';	if (stat(cp ? local : ".", &st) < 0) {		perror_reply(553, cp ? local : ".");		return ((char *) 0);	}	if (cp)		*cp = '/';	(void) strcpy(new, local);	cp = new + strlen(new);	*cp++ = '.';	for (count = 1; count < 100; count++) {		(void)sprintf(cp, "%d", count);		if (stat(new, &st) < 0)			return (new);	}	reply(452, "Unique file name cannot be created.");	return (NULL);}