Пример #1
0
void
statfilecmd (const char *filename)
{
  FILE *fin;
  int c;
  char line[LINE_MAX];

  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");
	      ftpd_pclose (fin);
	      dologout (1);
	    }
	  if (ferror (fin))
	    {
	      perror_reply (551, filename);
	      ftpd_pclose (fin);
	      return;
	    }
	  putc ('\r', stdout);
	}
      putc (c, stdout);
    }
  ftpd_pclose (fin);
  reply (211, "End of Status");
}
Пример #2
0
void
cwd(const char *path)
{

	if (chdir(path) < 0)
		perror_reply(550, path);
	else {
		show_chdir_messages(250);
		ack("CWD");
		if (getcwd(cached_path, MAXPATHLEN) == NULL) {
			discover_path(cached_path, path);
		}
	}
}
Пример #3
0
/* 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);
    }
  /*  (void) strcpy (string, s); */
  memcpy (string, s, len);
  return string;
}
Пример #4
0
void
store (const char *name, const char *mode, int unique)
{
  FILE *fout, *din;
  struct stat st;
  int (*closefunc) (FILE *);

  if (unique && stat (name, &st) == 0)
    {
      const char *name_unique = gunique (name);
      
      if (name_unique)
        name = name_unique;
      else
        {
          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)
    {
      if (unique)
	reply (226, "Transfer complete (unique file name:%s).", name);
      else
	reply (226, "Transfer complete.");
    }
  fclose (din);
  data = -1;
  pdata = -1;
done:
  LOGBYTES (*mode == 'w' ? "put" : "append", name, byte_count);
  (*closefunc) (fout);
}
Пример #5
0
void
retrieve (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);
}
Пример #6
0
int
main (int argc, char *argv[], char **envp)
{
  int index;

  set_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 */

  /* Parse the command line */
  iu_argp_init ("ftpd", default_program_authors);
  argp_parse (&argp, argc, argv, 0, &index, NULL);
  
  /* Bail out, wrong usage */
  argc -= index;
  if (argc != 0)
    error (1, 0, "surplus arguments; try `%s --help' for more info",
	   program_name);

  /* 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
    {
      socklen_t 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.  */
  {
    socklen_t 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");
  }
#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 ();
}
Пример #7
0
/* 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 int
receive_data (FILE * instr, FILE * 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;
	      c = getc (instr);
	      if (c != '\n')
		{
		  putc ('\r', outstr);
		  if (c == '\0' || c == EOF)
		    goto contin2;
		}
	    }
	  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);
	  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;
}
Пример #8
0
/* 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 void
send_data (FILE * instr, FILE * outstr, off_t blksize)
{
  int c, cnt, filefd, netfd;
  char *buf, *bp;
  off_t curpos;
  size_t len, filesize;

  transflag++;
  if (setjmp (urgcatch))
    {
      transflag = 0;
      return;
    }

  netfd = fileno (outstr);
  filefd = fileno (instr);
#ifdef HAVE_MMAP
  if (file_size > 0)
    {
      curpos = lseek (filefd, 0, SEEK_CUR);
      if (curpos >= 0)
	{
	  filesize = file_size - curpos;
	  buf = mmap (0, filesize, PROT_READ, MAP_SHARED, filefd, curpos);
	}
    }
#endif

  switch (type)
    {

    case TYPE_A:
#ifdef HAVE_MMAP
      if (file_size > 0 && curpos >= 0 && buf != MAP_FAILED)
	{
	  len = 0;
	  while (len < filesize)
	    {
	      byte_count++;
	      if (buf[len] == '\n')
		{
		  if (ferror (outstr))
		    break;
		  putc ('\r', outstr);
		}
	      putc (buf[len], outstr);
	      len++;
	    }
	  fflush (outstr);
	  transflag = 0;
	  munmap (buf, filesize);
	  if (ferror (outstr))
	    goto data_err;
	  reply (226, "Transfer complete.");
	  return;
	}
#endif
      while ((c = getc (instr)) != EOF)
	{
	  byte_count++;
	  if (c == '\n')
	    {
	      if (ferror (outstr))
		goto data_err;
	      putc ('\r', outstr);
	    }
	  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:
#ifdef HAVE_MMAP
      if (file_size > 0 && curpos >= 0 && buf != MAP_FAILED)
	{
	  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;
	}
#endif
      buf = malloc ((u_int) blksize);
      if (buf == 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;
      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");
}
Пример #9
0
static FILE *
dataconn (const char *name, off_t size, const char *mode)
{
  char sizebuf[32];
  FILE *file;
  int retry = 0;

  file_size = size;
  byte_count = 0;
  if (size != (off_t) - 1)
    snprintf (sizebuf, sizeof (sizebuf), " (%s bytes)", off_to_str (size));
  else
    *sizebuf = '\0';
  if (pdata >= 0)
    {
      struct sockaddr_in from;
      socklen_t s; 
      socklen_t fromlen = sizeof (from);

      signal (SIGALRM, toolong);
      alarm ((unsigned) timeout);
      s = accept (pdata, (struct sockaddr *) &from, &fromlen);
      alarm (0);
      if (s < 0)
	{
	  reply (425, "Can't open data connection.");
	  close (pdata);
	  pdata = -1;
	  return NULL;
	}
      close (pdata);
      pdata = s;
#if defined (IP_TOS) && defined (IPTOS_THROUGHPUT) && defined (IPPROTO_IP)
      /* Optimize throughput.  */
      {
	int tos = IPTOS_THROUGHPUT;
	setsockopt (s, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof (int));
      }
#endif
#ifdef SO_KEEPALIVE
      /* Set keepalives on the socket to detect dropped conns.  */
      {
	int keepalive = 1;
	setsockopt (s, SOL_SOCKET, SO_KEEPALIVE,
		    (char *) &keepalive, 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);
  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");
      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;
}