⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\	The Regents of the University of California.  All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)ftpd.c	8.4 (Berkeley) 4/16/94";#endif /* not lint *//* * FTP server. */#include <sys/param.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#define	FTP_NAMES#include <arpa/ftp.h>#include <arpa/inet.h>#include <arpa/telnet.h>#include <ctype.h>#include <dirent.h>#include <err.h>#include <errno.h>#include <fcntl.h>#include <glob.h>#include <limits.h>#include <netdb.h>#include <pwd.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#include <time.h>#include <unistd.h>#include "pathnames.h"#include "extern.h"#if __STDC__#include <stdarg.h>#else#include <varargs.h>#endifstatic char version[] = "Version 6.00";extern	off_t restart_point;extern	char cbuf[];struct	sockaddr_in ctrl_addr;struct	sockaddr_in data_source;struct	sockaddr_in data_dest;struct	sockaddr_in his_addr;struct	sockaddr_in pasv_addr;int	data;jmp_buf	errcatch, urgcatch;int	logged_in;struct	passwd *pw;int	debug;int	timeout = 900;    /* timeout after 15 minutes of inactivity */int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */int	logging;int	guest;int	type;int	form;int	stru;			/* avoid C keyword */int	mode;int	usedefault = 1;		/* for data transfers */int	pdata = -1;		/* for passive mode */sig_atomic_t transflag;off_t	file_size;off_t	byte_count;#if !defined(CMASK) || CMASK == 0#undef CMASK#define CMASK 027#endifint	defumask = CMASK;		/* default umask value */char	tmpline[7];char	hostname[MAXHOSTNAMELEN];char	remotehost[MAXHOSTNAMELEN];/* * Timeout intervals for retrying connections * to hosts that don't accept PORT cmds.  This * is a kludge, but given the problems with TCP... */#define	SWAITMAX	90	/* wait at most 90 seconds */#define	SWAITINT	5	/* interval between retries */int	swaitmax = SWAITMAX;int	swaitint = SWAITINT;#ifdef SETPROCTITLEchar	**Argv = NULL;		/* pointer to argument vector */char	*LastArgv = NULL;	/* end of argv */char	proctitle[LINE_MAX];	/* initial part of title */#endif /* SETPROCTITLE */#define LOGCMD(cmd, file) \	if (logging > 1) \	    syslog(LOG_INFO,"%s %s%s", cmd, \		*(file) == '/' ? "" : curdir(), file);#define LOGCMD2(cmd, file1, file2) \	 if (logging > 1) \	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \		*(file1) == '/' ? "" : curdir(), file1, \		*(file2) == '/' ? "" : curdir(), file2);#define LOGBYTES(cmd, file, cnt) \	if (logging > 1) { \		if (cnt == (off_t)-1) \		    syslog(LOG_INFO,"%s %s%s", cmd, \			*(file) == '/' ? "" : curdir(), file); \		else \		    syslog(LOG_INFO, "%s %s%s = %qd bytes", \			cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \	}static void	 ack __P((char *));static void	 myoob __P((int));static int	 checkuser __P((char *));static FILE	*dataconn __P((char *, off_t, char *));static void	 dolog __P((struct sockaddr_in *));static char	*curdir __P((void));static void	 end_login __P((void));static FILE	*getdatasock __P((char *));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));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;#ifdef SETPROCTITLE	/*	 *  Save start and extent of argv for setproctitle.	 */	Argv = argv;	while (*envp)		envp++;	LastArgv = envp[-1] + strlen(envp[-1]);#endif /* SETPROCTITLE */	while ((ch = getopt(argc, argv, "dlt:T:u:v")) != 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 '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 ((int)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);}static char ttyline[20];/* * 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;		}		end_login();	}	guest = 0;	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {		if (checkuser("ftp") || checkuser("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(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);	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 _PATH_FTPUSERS */static intcheckuser(name)	char *name;{	FILE *fd;	int found = 0;	char *p, line[BUFSIZ];	if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {		while (fgets(line, sizeof(line), fd) != NULL)			if ((p = strchr(line, '\n')) != NULL) {				*p = '\0';				if (line[0] == '#')					continue;				if (strcmp(p, 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, "", "");	pw = NULL;	logged_in = 0;	guest = 0;}voidpass(passwd)	char *passwd;{	char *salt, *xpasswd;	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)			salt = "xx";		else			salt = pw->pw_passwd;		xpasswd = crypt(passwd, salt);		/* The strcmp does not catch null passwords! */		if (pw == NULL || *pw->pw_passwd == '\0' ||		    strcmp(xpasswd, pw->pw_passwd)) {			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;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -