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

📄 ftpd.c

📁 伯克利大学的一个ftp协议的实现源代码,包括客户端和服务器端.
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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. *//*  * From: @(#)ftpd.c	8.4 (Berkeley) 4/16/94 * From: NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp * From: OpenBSD: ftpd.c,v 1.26 1996/12/07 09:00:22 bitblt Exp * From: OpenBSD: ftpd.c,v 1.35 1997/05/01 14:45:37 deraadt Exp */char ftpd_rcsid[] =   "$Id: ftpd.c,v 1.8 1997/06/09 01:04:59 dholland Exp $";char copyright[] =  "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n"  "     The Regents of the University of California.  All rights reserved.\n";/* * FTP server. */#include <sys/param.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/wait.h>#include <sys/mman.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/tcp.h>#define	FTP_NAMES#include <arpa/ftp.h>#include <arpa/inet.h>#include <arpa/telnet.h>#include <ctype.h>#include <dirent.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 <vis.h>#include <unistd.h>#include <utmp.h>#ifndef __linux__#include <err.h>#else#include <grp.h>       /* for initgroups() */#include <sys/file.h>  /* for L_SET et al. */typedef int64_t quad_t;#endif#ifndef MAP_FAILED#define MAP_FAILED ((void *)-1)#endif#ifdef USE_SHADOW#include <shadow.h>#include "isexpired.h"#endif#include "pathnames.h"#include "extern.h"#if __STDC__#include <stdarg.h>#else#include <varargs.h>#endifstatic char version[] = "Version 6.2/OpenBSD/Linux-0.10";extern	off_t restart_point;extern	char cbuf[];struct	sockaddr_in server_addr;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	daemon_mode = 0;int	data;jmp_buf	errcatch, urgcatch;int	logged_in;struct	passwd *pw;#ifdef USE_SHADOWstruct	spwd *spw = NULL;#endifint	debug = 0;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	high_data_ports = 0;int	anon_only = 0;int	multihome = 0;int	guest;int	stats;int	statfd = -1;int	dochroot;int	type;int	form;int	stru;			/* avoid C keyword */int	mode;int	doutmp = 0;		/* update utmp file */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];char	dhostname[MAXHOSTNAMELEN];char	*guestpw;static char ttyline[20];char	*tty = ttyline;		/* for klogin */static struct utmp utmp;	/* for utmp */#if defined(KERBEROS)int	notickets = 1;char	*krbtkfile_env = NULL;#endifchar	*ident = NULL;/* * 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 HASSETPROCTITLEchar	proctitle[BUFSIZ];	/* initial part of title */#endif /* HASSETPROCTITLE */#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, (quad_t)(cnt)); \	}static void	 ack __P((const char *));static void	 myoob __P((int));static int	 checkuser __P((const char *, const char *));static FILE	*dataconn __P((const char *, off_t, const char *));static void	 dolog __P((struct sockaddr_in *));static const char	*curdir __P((void));static void	 end_login __P((void));static FILE	*getdatasock __P((const char *));static int	guniquefd __P((const char *, char **));static void	 lostconn __P((int));static void	 sigquit __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((const char *));static char	*sgetsave __P((char *));static void	 reapchild __P((int));void	 logxfer __P((const char *, off_t, time_t));#ifdef __linux__static void warnx(const char *format, ...) {	va_list ap;	va_start(ap, format);	fprintf(stderr, "ftpd: ");	vfprintf(stderr, format, ap);	fprintf(stderr, "\n");	va_end(ap);}#endif /* __linux__ */static const char *curdir(void){	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(int argc, char *argv[], char **envp){	int addrlen, ch, on = 1, tos;	char *cp, line[LINE_MAX];	FILE *fd;	const char *argstr = "AdDhlMSt:T:u:Uv";	struct hostent *hp;	void (*sigreturn)(int);	initsetproctitle(argc, argv, envp);	tzset();	/* in case no timezone database in ~ftp */	/* set this here so klogin can use it... */	(void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());	while ((ch = getopt(argc, argv, argstr)) != -1) {		switch (ch) {		case 'A':			anon_only = 1;			break;		case 'd':			debug = 1;			break;		case 'D':			daemon_mode = 1;			break;		case 'h':			high_data_ports = 1;			break;		case 'l':			logging++;	/* > 1 == extra logging */			break;		case 'M':			multihome = 1;			break;		case 'S':			stats = 1;			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);	/*	 * LOG_NDELAY sets up the logging connection immediately,	 * necessary for anonymous ftp's that chroot and can't do it later.	 */#ifndef LOG_FTP#define LOG_FTP LOG_DAEMON#endif	openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);	if (daemon_mode) {		int ctl_sock, fd2;		struct servent *sv;		/*		 * Detach from parent.		 */		if (daemon(1, 1) < 0) {			syslog(LOG_ERR, "failed to become a daemon");			exit(1);		}		(void) signal(SIGCHLD, reapchild);		/*		 * Get port number for ftp/tcp.		 */		sv = getservbyname("ftp", "tcp");		if (sv == NULL) {			syslog(LOG_ERR, "getservbyname for ftp failed");			exit(1);		}		/*		 * Open a socket, bind it to the FTP port, and start		 * listening.		 */		ctl_sock = socket(AF_INET, SOCK_STREAM, 0);		if (ctl_sock < 0) {			syslog(LOG_ERR, "control socket: %m");			exit(1);		}		if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR,		    (char *)&on, sizeof(on)) < 0)			syslog(LOG_ERR, "control setsockopt: %m");;		server_addr.sin_family = AF_INET;		server_addr.sin_addr.s_addr = INADDR_ANY;		server_addr.sin_port = sv->s_port;		if (bind(ctl_sock, (struct sockaddr *)&server_addr,			 sizeof(server_addr))) {			syslog(LOG_ERR, "control bind: %m");			exit(1);		}		if (listen(ctl_sock, 32) < 0) {			syslog(LOG_ERR, "control listen: %m");			exit(1);		}		/*		 * Loop forever accepting connection requests and forking off		 * children to handle them.		 */		while (1) {			addrlen = sizeof(his_addr);			fd2 = accept(ctl_sock, (struct sockaddr *)&his_addr,				    &addrlen);			if (fork() == 0) {				/* child */				(void) dup2(fd2, 0);				(void) dup2(fd2, 1);				close(ctl_sock);				break;			}			close(fd2);		}	} else {		addrlen = sizeof(his_addr);		if (getpeername(0, (struct sockaddr *)&his_addr,			        &addrlen) < 0) {			syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);			exit(1);		}	}	(void) signal(SIGHUP, sigquit);	(void) signal(SIGINT, sigquit);	(void) signal(SIGQUIT, sigquit);	(void) signal(SIGTERM, sigquit);	(void) signal(SIGPIPE, lostconn);	(void) signal(SIGCHLD, SIG_IGN);	sigreturn = signal(SIGURG, myoob);	if ((long)sigreturn < 0)		syslog(LOG_ERR, "signal: %m");	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);	/* 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));	/* Make sure hostname is fully qualified. */	hp = gethostbyname(hostname);	if (hp != NULL)		strcpy (hostname, hp->h_name);	if (multihome) {		hp = gethostbyaddr((char *) &ctrl_addr.sin_addr,				   sizeof (struct in_addr), AF_INET);		if (hp != NULL) {			strcpy (dhostname, hp->h_name);		} else {			/* Default. */			strcpy (dhostname, inet_ntoa(ctrl_addr.sin_addr));		}	}	reply(220, "%s FTP server (%s) ready.",	      (multihome ? dhostname : hostname), version);	(void) setjmp(errcatch);	for (;;)		(void) yyparse();	/* NOTREACHED */}/* * Signal handlers. */static voidlostconn(int signo){	(void)signo;	if (debug)		syslog(LOG_DEBUG, "lost connection");	dologout(-1);}static voidsigquit(signo)	int signo;{	syslog(LOG_ERR, "got signal %s", strsignal(signo));	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);

⌨️ 快捷键说明

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