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

📄 ftpd.c

📁 linux下ftpd服务器端的源码实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* - Ftp Server * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994, 2002 *	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. * 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. */#if 0static char sccsid[] = "@(#)ftpd.c	8.5 (Berkeley) 4/28/95";#endif/* * FTP server. */#ifdef HAVE_CONFIG_H# include <config.h>#endif#if !defined (__GNUC__) && defined (_AIX)#pragma alloca#endif#ifndef alloca /* Make alloca work the best possible way.  */# ifdef __GNUC__#  define alloca __builtin_alloca# else /* not __GNUC__ */#  if HAVE_ALLOCA_H#   include <alloca.h>#  else /* not __GNUC__ or HAVE_ALLOCA_H */#    ifndef _AIX /* Already did AIX, up at the top.  */       char *alloca ();#    endif /* not _AIX */#  endif /* not HAVE_ALLOCA_H */# endif /* not __GNUC__ */#endif /* not alloca */#include <sys/param.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/socket.h>#ifdef HAVE_SYS_WAIT_H#  include <sys/wait.h>#endif#include <netinet/in.h>#ifdef HAVE_NETINET_IN_SYSTM_H#  include <netinet/in_systm.h>#endif#ifdef HAVE_NETINET_IP_H#  include <netinet/ip.h>#endif#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 <getopt.h>#include <limits.h>#include <netdb.h>#include <setjmp.h>#include <signal.h>#include <grp.h>#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__#  include <stdarg.h>#else#  include <varargs.h>#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <syslog.h>#ifdef TIME_WITH_SYS_TIME#  include <sys/time.h>#  include <time.h>#else#  ifdef HAVE_SYS_TIME_H#    include <sys/time.h>#  else#    include <time.h>#  endif#endif#include <unistd.h>#ifdef HAVE_MMAP#include <sys/mman.h>#endif/* Include glob.h last, because it may define "const" which breaks   system headers on some platforms. */#include <glob.h>#include <libinetutils.h>#include "extern.h"#ifndef LINE_MAX# define LINE_MAX 2048#endif#ifndef LOG_FTP# define LOG_FTP LOG_DAEMON	/* Use generic facility.  */#endif#ifndef MAP_FAILED# define MAP_FAILED (void*)-1#endif#if !HAVE_DECL_FCLOSE/* Some systems don't declare fclose in <stdio.h>, so do it ourselves.  */extern int fclose (FILE *);#endifchar *program_name;/* Exported to ftpcmd.h.  */struct	sockaddr_in data_dest; /* Data port.  */struct	sockaddr_in his_addr;  /* Peer address.  */int	logging;               /* Enable log to syslog.  */int	type = TYPE_A;         /* Default TYPE_A.  */int	form = FORM_N;                  /* Default FORM_N.  */int	debug;                 /* Enable debug mode if 1.  */int	timeout = 900;         /* Timeout after 15 minutes of inactivity.  */int	maxtimeout = 7200;     /* Don't allow idle time to be set				  beyond 2 hours.  */int	pdata = -1;            /* For passive mode.  */char	*hostname;             /* Who we are.  */int	usedefault = 1;	       /* For data transfers.  */char	tmpline[7];            /* Temp buffer use in OOB.  *//* Requester credentials.  */struct credentials cred;static struct  sockaddr_in ctrl_addr;    /* Control address.  */static struct  sockaddr_in data_source;  /* Port address.  */static struct  sockaddr_in pasv_addr;    /* Pasv address.  */static int      data = -1;       /* Port data connection socket.  */static jmp_buf  urgcatch;static int      stru = STRU_F;     /* Avoid C keyword.  */static int      stru_mode = MODE_S;/* Default STRU mode stru_mode = MODE_S.  */static int      anon_only;       /* Allow only anonymous login.  */static int      no_version;      /* Don't print version to client.  */static int      daemon_mode;     /* Start in daemon mode.  */static off_t    file_size;static off_t    byte_count;static sig_atomic_t transflag;   /* Flag where in a middle of transfer.  */static const char *pid_file = PATH_FTPDPID;#if !defined(CMASK) || CMASK == 0#undef CMASK#define CMASK 027#endifstatic int  defumask = CMASK;    /* Default umask value.  */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.  */static char ttyline[20];         /* Line to log in utmp.  */#define NUM_SIMUL_OFF_TO_STRS 4/* Returns a string with the decimal representation of the off_t OFF, taking   into account that off_t might be longer than a long.  The return value is   a pointer to a static buffer, but a return value will only be reused every   NUM_SIMUL_OFF_TO_STRS calls, to allow multiple off_t's to be conveniently   printed with a single printf statement.  */static char *off_to_str (off_t off){  static char bufs[NUM_SIMUL_OFF_TO_STRS][80];  static char (*next_buf)[80] = bufs;  if (next_buf >= (bufs+NUM_SIMUL_OFF_TO_STRS))    next_buf = bufs;  if (sizeof (off) > sizeof (long))    sprintf (*next_buf, "%qd", off);  else if (sizeof (off) == sizeof (long))    sprintf (*next_buf, "%ld", off);  else    sprintf (*next_buf, "%d", off);  return *next_buf++;}/* * 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 */static int swaitmax = SWAITMAX;static int swaitint = SWAITINT;#ifdef HAVE_SETPROCTITLEchar	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 = %s bytes", \			cmd, (*(file) == '/') ? "" : curdir(), file, \			   off_to_str (cnt)); \	}static void ack (const char *);static void authentication_setup (const char *);#ifdef HAVE_LIBWRAPstatic int  check_host (struct sockaddr *sa);#endifstatic void complete_login (struct credentials *);static char *curdir (void);static FILE *dataconn (const char *, off_t, const char *);static void dolog (struct sockaddr_in *, struct credentials *);static void end_login (struct credentials *);static FILE *getdatasock (const char *);static char *gunique (const char *);static void lostconn (int);static void myoob (int);static int  receive_data (FILE *, FILE *);static void send_data (FILE *, FILE *, off_t);static void sigquit (int);static void usage (int);static const char *short_options = "Aa:Ddlp:qt:T:u:";static struct option long_options[] ={  { "anonymous-only", no_argument, 0, 'A' },  { "auth", required_argument, 0, 'a' },  { "daemon", no_argument, 0, 'D' },  { "debug", no_argument, 0, 'd' },  { "help", no_argument, 0, '&' },  { "logging", no_argument, 0, 'l' },  { "pidfile", required_argument, 0, 'p' },  { "no-version", no_argument, 0, 'q' },  { "timeout", required_argument, 0, 't' },  { "max-timeout", required_argument, 0, 'T' },  { "umask", required_argument, 0, 'u' },  { "version", no_argument, 0, 'V' },  { 0, 0, 0, 0 }};static voidusage (int err){  if (err != 0)    {      fprintf (stderr, "Usage: %s [OPTION] ...\n", program_name);      fprintf (stderr, "Try `%s --help' for more information.\n", program_name);    }  else    {      fprintf (stdout, "Usage: %s [OPTION] ...\n", program_name);      puts ("Internet File Transfer Protocol server.\n\n\  -A, --anonymous-only      Server configure for anonymous service only\n\  -D, --daemon              Start the ftpd standalone\n\  -d, --debug               Debug mode\n\  -l, --logging             Increase verbosity of syslog messages\n\  -p, --pidfile=[PIDFILE]   Change default location of pidfile\n\  -q, --no-version          Do not display version in banner\n\  -t, --timeout=[TIMEOUT]   Set default idle timeout\n\  -T, --max-timeout         Reset maximum value of timeout allowed\n\  -u, --umask               Set default umask(base 8)\n\      --help                Print this message\n\  -V, --version             Print version\n\  -a, --auth=[AUTH]         Use AUTH for authentication, it can be:\n\                               default     passwd authentication.");#ifdef WITH_PAM      puts ("\                               pam         using pam 'ftp' module.");#endif#ifdef WITH_KERBEROS      puts ("\                               kerberos");#endif#ifdef WITH_KERBEROS5      puts ("\                               kderberos5");#endif#ifdef WITH_OPIE      puts ("\                               opie");#endif      fprintf (stdout, "\nSubmit bug reports to %s.\n", PACKAGE_BUGREPORT);    }  exit (err);}intmain(int argc, char *argv[], char **envp){  int option;  program_name = argv[0];#ifdef HAVE_TZSET  tzset(); /* In case no timezone database in ~ftp.  */#endif#ifdef HAVE_INITSETPROCTITLE  /* Save start and extent of argv for setproctitle.  */  initsetproctitle (argc, argv, envp);#endif /* HAVE_INITSETPROCTITLE */  while ((option = getopt_long (argc, argv, short_options,				long_options, NULL)) != EOF)    {      switch (option)	{	case 'A': /* Anonymous ftp only.  */	  anon_only = 1;	  break;	case 'a': /* Authentification method.  */	  if (strcasecmp (optarg, "default") == 0)	    cred.auth_type = AUTH_TYPE_PASSWD;#ifdef WITH_PAM	  else if (strcasecmp (optarg, "pam") == 0)	    cred.auth_type = AUTH_TYPE_PAM;#endif#ifdef WITH_KERBEROS	  else if (stracasecmp (optarg, "kerberos") == 0)	    cred.auth_type = AUTH_TYPE_KERBEROS;#endif#ifdef WITH_KERBEROS5	  else if (stracasecmp (optarg, "kerberos5") == 0)	    cred.auth_type = AUTH_TYPE_KERBEROS5;#endif#ifdef WITH_OPIE	  else if (stracasecmp (optarg, "opie") == 0)	    cred.auth_type = AUTH_TYPE_OPIE;#endif	  break;	case 'D': /* Run ftpd as daemon.  */	  daemon_mode = 1;	  break;	case 'd': /* Enable debug mode.  */	  debug = 1;	  break;	case 'l': /* Increase logging level.  */	  logging++;	/* > 1 == Extra logging.  */	  break;	case 'p': /* Override pid file */	  pid_file = optarg;	  break;	case 'q': /* Don't include version number in banner.  */	  no_version = 1;	  break;	case 't': /* Set default timeout value.  */	  timeout = atoi (optarg);	  if (maxtimeout < timeout)	    maxtimeout = timeout;	  break;	case 'T': /* Maximum timeout allowed.  */	  maxtimeout = atoi (optarg);	  if (timeout > maxtimeout)	    timeout = maxtimeout;	  break;	case 'u': /* Set umask.  */	  {	    long val = 0;	    val = strtol (optarg, &optarg, 8);	    if (*optarg != '\0' || val < 0)	      fprintf (stderr, "%s: bad value for -u", argv[0]);	    else	      defumask = val;	    break;	  }	case '&': /* Usage.  */	  usage (0);	  /* Not reached.  */	case 'V': /* Version.  */	  printf ("ftpd (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);	  exit (0);	case '?':	default:	  usage (1);	  /* Not reached.  */	}    }  /* Bail out, wrong usage */  argc -= optind;  if (argc != 0)    usage (1);  /* 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);  freopen (PATH_DEVNULL, "w", stderr);  /* If not running via inetd, we detach and dup(fd, 0), dup(fd, 1) the     fd = accept(). tcpd is check if compile with the support  */  if (daemon_mode)    {      if (server_mode (pid_file, &his_addr) < 0)	exit (1);    }  else    {      int addrlen = sizeof (his_addr);      if (getpeername (STDIN_FILENO, (struct sockaddr *)&his_addr,		       &addrlen) < 0)	{	  syslog (LOG_ERR, "getpeername (%s): %m", program_name);	  exit (1);	}    }  signal (SIGHUP, sigquit);  signal (SIGINT, sigquit);  signal (SIGQUIT, sigquit);  signal (SIGTERM, sigquit);  signal (SIGPIPE, lostconn);  signal (SIGCHLD, SIG_IGN);  if (signal (SIGURG, myoob) == SIG_ERR)    syslog (LOG_ERR, "signal: %m");  /* Get info on the ctrl connection.  */  {    int addrlen = sizeof (ctrl_addr);    if (getsockname (STDIN_FILENO, (struct sockaddr *)&ctrl_addr,		     &addrlen) < 0)      {	syslog (LOG_ERR, "getsockname (%s): %m", program_name);	exit (1);      }  }#if defined (IP_TOS) && defined (IPTOS_LOWDELAY) && defined (IPPROTO_IP)  /* To  minimize delays for interactive traffic.  */  {    int tos = IPTOS_LOWDELAY;    if (setsockopt (STDIN_FILENO, IPPROTO_IP, IP_TOS,		    (char *)&tos, sizeof(int)) < 0)      syslog (LOG_WARNING, "setsockopt (IP_TOS): %m");  }#endif#ifdef SO_OOBINLINE  /* Try to handle urgent data inline.  */  {    int on = 1;    if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE,		    (char *)&on, sizeof (on)) < 0)      syslog (LOG_ERR, "setsockopt: %m");

⌨️ 快捷键说明

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