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

📄 ftpd.c

📁 linux下ftpd服务器端的源码实现
💻 C
📖 第 1 页 / 共 4 页
字号:
  }#endif#ifdef SO_KEEPALIVE  /* Set keepalives on the socket to detect dropped connections.  */  {    int keepalive = 1;    if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,		    (char *)&keepalive, sizeof (keepalive)) < 0)      syslog (LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");  }#endif#ifdef	F_SETOWN  if (fcntl (STDIN_FILENO, F_SETOWN, getpid ()) == -1)    syslog (LOG_ERR, "fcntl F_SETOWN: %m");#endif  dolog (&his_addr, &cred);  /* Deal with login disable.  */  if (display_file (PATH_NOLOGIN, 530) == 0)    {      reply (530, "System not available.");      exit (0);    }  /* Display a Welcome message if exists,     N.B. reply(220,) must follow.  */  display_file (PATH_FTPWELCOME, 220);  hostname = localhost ();  if (! hostname)    perror_reply (550, "Local resource failure: malloc");  /* Tell them we're ready to roll.  */  if (!no_version)    reply (220, "%s FTP server (%s %s) ready.",	   hostname, PACKAGE_NAME, PACKAGE_VERSION);  else    reply (220, "%s FTP server ready.", hostname);  /* Set the jump, if we have an error parsing,     come here and start fresh.  */  setjmp (errcatch);  /* Roll.  */  for (;;)    yyparse ();  /* NOTREACHED */}static char *curdir (void){  static char *path = 0;  extern char *xgetcwd (void);  if (path)    free (path);  path = xgetcwd ();  if (! path)    return  (char *)"";  if (path[1] != '\0')	/* special case for root dir. */    {      char *tmp = realloc (path, strlen (path) + 2); /* '/' + '\0' */      if (! tmp)	{	  free(path);	  return (char *)"";	}      strcat(tmp, "/");      path = tmp;    }  /* For guest account, skip / since it's chrooted */  return (cred.guest ? path+1 : path);}static RETSIGTYPEsigquit (int signo){  syslog (LOG_ERR, "got signal %s", strsignal (signo));  dologout (-1);}static RETSIGTYPElostconn (int signo ARG_UNUSED){  signo;  if (debug)    syslog (LOG_DEBUG, "lost connection");  dologout (-1);}/* Helper function.  */char *sgetsave (const char *s){  char *string;  size_t len;  if (s == NULL)    s = "";  len = strlen (s) + 1;  string = malloc (len);  if (string == NULL)    {      perror_reply (421, "Local resource failure: malloc");      dologout (1);      /* NOTREACHED */    }  /*  (void) strcpy (string, s); */  memcpy (string, s, len);  return string;}static voidcomplete_login (struct credentials *pcred){  if (setegid ((gid_t)pcred->gid) < 0)    {      reply (550, "Can't set gid.");      return;    }#ifdef HAVE_INITGROUPS  initgroups (pcred->name, pcred->gid);#endif  /* open wtmp before chroot */  snprintf (ttyline, sizeof (ttyline), "ftp%d", getpid ());  logwtmp_keep_open (ttyline, pcred->name, pcred->remotehost);  if (pcred->guest)    {      /* We MUST do a chdir () after the chroot. Otherwise	 the old current directory will be accessible as "."	 outside the new root!  */      if (chroot (pcred->rootdir) < 0 || chdir (pcred->homedir) < 0)	{	  reply (550, "Can't set guest privileges.");	  goto bad;	}    }  else if (pcred->dochroot)    {      if (chroot (pcred->rootdir) < 0 || chdir(pcred->homedir) < 0)	{	  reply (550, "Can't change root.");	  goto bad;	}      setenv ("HOME", pcred->homedir, 1);    }  else if (chdir (pcred->rootdir) < 0)    {      if (chdir ("/") < 0)	{	  reply (530, "User %s: can't change directory to %s.",		 pcred->name, pcred->homedir);	  goto bad;	}      else	lreply (230, "No directory! Logging in with home=/");    }  if (seteuid ((uid_t)pcred->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.  */  display_file (PATH_FTPLOGINMESG, 230);  if (pcred->guest)    {      reply (230, "Guest login ok, access restrictions apply.");#ifdef HAVE_SETPROCTITLE      snprintf (proctitle, sizeof (proctitle), "%s: anonymous",		pcred->remotehost);      setproctitle ("%s",proctitle);#endif /* HAVE_SETPROCTITLE */      if (logging)	syslog (LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s",		pcred->remotehost);    }  else    {      reply (230, "User %s logged in.", pcred->name);#ifdef HAVE_SETPROCTITLE      snprintf (proctitle, sizeof (proctitle),		"%s: %s", pcred->remotehost, pcred->name);      setproctitle ("%s",proctitle);#endif /* HAVE_SETPROCTITLE */      if (logging)	syslog (LOG_INFO, "FTP LOGIN FROM %s as %s",		pcred->remotehost, pcred->name);    }  umask(defumask);  return;bad:  /* Forget all about it... */  end_login (pcred);}/* 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.  */voiduser (const char *name){  if (cred.logged_in)    {      if (cred.guest || cred.dochroot)	{	  reply (530, "Can't change user from guest login.");	  return;	}      end_login (&cred);    }  /* Non zero means failed.  */  if (auth_user (name, &cred) != 0)    {      /* If they gave us a reason.  */      if (cred.message)	{	  reply (530, "%s", cred.message);	  free (cred.message);	  cred.message = NULL;	}      else	reply (530, "User %s access denied.", name);      if (logging)	syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",	       cred.remotehost, name);      return;    }  /* If the server is set to serve anonymous service only     the request have to come from a guest or a chrooted.  */  if (anon_only && !cred.guest && !cred.dochroot)    {      reply (530, "Sorry, only anonymous ftp allowed");      return;    }  if (logging)    {      strncpy (curname, name, sizeof (curname) - 1);      curname [sizeof (curname) - 1] = '\0'; /* Make sure null terminated.  */    }  if (cred.message)    {      reply (331, "%s", cred.message);      free (cred.message);      cred.message = NULL;    }  else    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);}/* Terminate login as previous user, if any, resetting state;   used when USER command is given or login fails.  */static voidend_login (struct credentials *pcred){  char *remotehost = pcred->remotehost;  int atype = pcred->auth_type;  seteuid ((uid_t)0);  if (pcred->logged_in)    logwtmp_keep_open (ttyline, "", "");  if (pcred->name)    free (pcred->name);  if (pcred->passwd)    {      memset (pcred->passwd, 0, strlen (pcred->passwd));      free (pcred->passwd);    }  if (pcred->homedir)    free (pcred->homedir);  if (pcred->rootdir)    free (pcred->rootdir);  if (pcred->shell)    free (pcred->shell);  if (pcred->pass) /* ??? */    {      memset (pcred->pass, 0, strlen (pcred->pass));      free (pcred->pass);    }  if (pcred->message)    free (pcred->message);  memset (pcred, 0, sizeof (*pcred));  pcred->remotehost = remotehost;  pcred->auth_type = atype;}voidpass (const char *passwd){  if (cred.logged_in || askpasswd == 0)    {      reply(503, "Login with USER first.");      return;    }  askpasswd = 0;  if (!cred.guest) /* "ftp" is the only account allowed no password.  */    {      /* Try to authenticate the user.  Failed if != 0.  */      if (auth_pass (passwd, &cred) != 0)	{	  /* Any particular reasons.  */	  if (cred.message)	    {	      reply (530, "%s", cred.message);	      free (cred.message);	      cred.message = NULL;	    }	  else	    reply (530, "Login incorrect.");	  if (logging)	    syslog (LOG_NOTICE, "FTP LOGIN FAILED FROM %s, %s",		    cred.remotehost, curname);	  if (login_attempts++ >= 5)	    {	      syslog(LOG_NOTICE, "repeated login failures from %s",		     cred.remotehost);	      exit(0);	    }	  return;	}    }  cred.logged_in = 1; /* Everything seems to be allright.  */  complete_login (&cred);  login_attempts = 0; /* This time successful.  */}voidretrieve (const char *cmd, const char *name){  FILE *fin, *dout;  struct stat st;  int (*closefunc) (FILE *);  size_t buffer_size = 0;  if (cmd == 0)    {      fin = fopen (name, "r"), closefunc = fclose;      st.st_size = 0;    }  else    {      char line[BUFSIZ];      snprintf (line, sizeof line, cmd, name);      name = line;      fin = ftpd_popen (line, "r"), closefunc = ftpd_pclose;      st.st_size = -1;      buffer_size = 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)	    {	      c = getc (fin);	      if (c == EOF)		{		  perror_reply (550, name);		  goto done;		}	      if (c == '\n')		i++;	    }	}      else if (lseek (fileno (fin), restart_point, SEEK_SET) < 0)	{	  perror_reply (550, name);	  goto done;	}    }  dout = dataconn (name, st.st_size, "w");  if (dout == NULL)    goto done;  send_data (fin, dout, buffer_size);  fclose (dout);  data = -1;  pdata = -1;done:  if (cmd == 0)    LOGBYTES ("get", name, byte_count);  (*closefunc) (fin);}voidstore (const char *name, const char *mode, int unique){  FILE *fout, *din;  struct stat st;  int (*closefunc) (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)	    {	      c = getc (fout);	      if (c == 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, SEEK_CUR) < 0)	    {	      perror_reply (550, name);	      goto done;	    }	}      else if (lseek (fileno(fout), restart_point, SEEK_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)    {

⌨️ 快捷键说明

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