Esempio n. 1
0
/* XXX - really, this should be refactored into a "buffered writer" object */
static int
write_dir_list(struct vsf_session* p_sess, struct mystr_list* p_dir_list,
               enum EVSFRWTarget target)
{
  /* This function writes out a list of strings to the client, over the
   * data socket. We now coalesce the strings into fewer write() syscalls,
   * which saved 33% CPU time writing a large directory.
   */
  int retval = 0;
  unsigned int dir_index_max = str_list_get_length(p_dir_list);
  unsigned int dir_index;
  struct mystr buf_str = INIT_MYSTR;
  str_reserve(&buf_str, VSFTP_DIR_BUFSIZE);
  for (dir_index = 0; dir_index < dir_index_max; dir_index++)
  {
    str_append_str(&buf_str, str_list_get_pstr(p_dir_list, dir_index));
    if (dir_index == dir_index_max - 1 ||
        str_getlen(&buf_str) +
          str_getlen(str_list_get_pstr(p_dir_list, dir_index + 1)) >
            VSFTP_DIR_BUFSIZE)
    {
      /* Writeout needed - we're either at the end, or we filled the buffer */
      int writeret = ftp_write_str(p_sess, &buf_str, target);
      if (writeret != 0)
      {
        retval = 1;
        break;
      }
      str_empty(&buf_str);
    }
  }
  str_free(&buf_str);
  return retval;
}
Esempio n. 2
0
static void
ftp_write_str_common(struct vsf_session* p_sess, int status, char sep,
                     const struct mystr* p_str)
{
  static struct mystr s_write_buf_str;
  static struct mystr s_text_mangle_str;
  int retval;
  if (tunable_log_ftp_protocol)
  {
    str_alloc_ulong(&s_write_buf_str, (unsigned long) status);
    str_append_char(&s_write_buf_str, sep);
    str_append_str(&s_write_buf_str, p_str);
    vsf_log_line(p_sess, kVSFLogEntryFTPOutput, &s_write_buf_str);
  }
  str_copy(&s_text_mangle_str, p_str);
  /* Process the output response according to the specifications.. */
  /* Escape telnet characters properly */
  str_replace_text(&s_text_mangle_str, "\377", "\377\377");
  /* Change \n for \0 in response */
  str_replace_char(&s_text_mangle_str, '\n', '\0');
  /* Build string to squirt down network */
  str_alloc_ulong(&s_write_buf_str, (unsigned long) status);
  str_append_char(&s_write_buf_str, sep);
  str_append_str(&s_write_buf_str, &s_text_mangle_str);
  str_append_text(&s_write_buf_str, "\r\n");
  retval = ftp_write_str(p_sess, &s_write_buf_str, kVSFRWControl);
  if (retval != 0)
  {
    die("ftp_write");
  }
}
Esempio n. 3
0
void
vsf_cmdio_write_raw(struct vsf_session* p_sess, const char* p_text)
{
  static struct mystr s_the_str;
  int retval;
  str_alloc_text(&s_the_str, p_text);
  if (tunable_log_ftp_protocol)
  {
    vsf_log_line(p_sess, kVSFLogEntryFTPOutput, &s_the_str);
  }
  retval = ftp_write_str(p_sess, &s_the_str, kVSFRWControl);
  if (retval != 0)
  {
    die("ftp_write_str");
  }
}
Esempio n. 4
0
static void
process_ssl_slave_req(struct vsf_session* p_sess)
{
  while (1)
  {
    char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd);
    int retval;
    if (cmd == PRIV_SOCK_GET_USER_CMD)
    {
      ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf);
      priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
    }
    else if (cmd == PRIV_SOCK_WRITE_USER_RESP)
    {
      priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
      retval = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl);
      priv_sock_send_int(p_sess->ssl_slave_fd, retval);
    }
    else
    {
      die("bad request in process_ssl_slave_req");
    }
  }
}
Esempio n. 5
0
static int
transfer_dir_internal(struct vsf_session* p_sess, int is_control,
                      struct vsf_sysutil_dir* p_dir,
                      const struct mystr* p_base_dir_str,
                      const struct mystr* p_option_str,
                      const struct mystr* p_filter_str,
                      int is_verbose)
{
  struct mystr_list dir_list = INIT_STRLIST;
  struct mystr_list subdir_list = INIT_STRLIST;
  struct mystr dir_prefix_str = INIT_MYSTR;
  struct mystr_list* p_subdir_list = 0;
  struct str_locate_result loc_result = str_locate_char(p_option_str, 'R');
  int failed = 0;
  enum EVSFRWTarget target = kVSFRWData;
  if (is_control)
  {
    target = kVSFRWControl;
  }
  if (loc_result.found && tunable_ls_recurse_enable)
  {
    p_subdir_list = &subdir_list;
  }
  vsf_ls_populate_dir_list(&dir_list, p_subdir_list, p_dir, p_base_dir_str,
                           p_option_str, p_filter_str, is_verbose);
  if (p_subdir_list)
  {
    int retval;
    str_copy(&dir_prefix_str, p_base_dir_str);
    str_append_text(&dir_prefix_str, ":\r\n");
    retval = ftp_write_str(p_sess, &dir_prefix_str, target);
    if (retval != 0)
    {
      failed = 1;
    }
  }
  if (!failed)
  {
    failed = write_dir_list(p_sess, &dir_list, target);
  }
  /* Recurse into the subdirectories if required... */
  if (!failed)
  {
    struct mystr sub_str = INIT_MYSTR;
    unsigned int num_subdirs = str_list_get_length(&subdir_list);
    unsigned int subdir_index;
    for (subdir_index = 0; subdir_index < num_subdirs; subdir_index++)
    {
      int retval;
      struct vsf_sysutil_dir* p_subdir;
      const struct mystr* p_subdir_str = 
        str_list_get_pstr(&subdir_list, subdir_index);
      if (str_equal_text(p_subdir_str, ".") ||
          str_equal_text(p_subdir_str, ".."))
      {
        continue;
      }
      str_copy(&sub_str, p_base_dir_str);
      str_append_char(&sub_str, '/');
      str_append_str(&sub_str, p_subdir_str);
      p_subdir = str_opendir(&sub_str);
      if (p_subdir == 0)
      {
        /* Unreadable, gone missing, etc. - no matter */
        continue;
      }
      str_alloc_text(&dir_prefix_str, "\r\n");
      retval = ftp_write_str(p_sess, &dir_prefix_str, target);
      if (retval != 0)
      {
        failed = 1;
        vsf_sysutil_closedir(p_subdir);
        break;
      }
      retval = transfer_dir_internal(p_sess, is_control, p_subdir, &sub_str,
                                     p_option_str, p_filter_str, is_verbose);
      vsf_sysutil_closedir(p_subdir);
      if (retval != 0)
      {
        failed = 1;
        break;
      }
    }
    str_free(&sub_str);
  }
  str_list_free(&dir_list);
  str_list_free(&subdir_list);
  str_free(&dir_prefix_str);
  if (!failed)
  {
    return 0;
  }
  else
  {
    return -1;
  }
}
Esempio n. 6
0
void
ssl_slave(struct vsf_session* p_sess)
{
  struct mystr data_str = INIT_MYSTR;
  str_reserve(&data_str, VSFTP_DATA_BUFSIZE);
  /* Before becoming the slave, clear the alarm for the FTP protocol. */
  vsf_sysutil_clear_alarm();
  /* No need for any further communications with the privileged parent. */
  priv_sock_set_parent_context(p_sess);
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("SSL handler");
  }
  while (1)
  {
    char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd);
    int ret;
    if (cmd == PRIV_SOCK_GET_USER_CMD)
    {
      ret = ftp_getline(p_sess, &p_sess->ftp_cmd_str,
                        p_sess->p_control_line_buf);
      priv_sock_send_int(p_sess->ssl_slave_fd, ret);
      if (ret >= 0)
      {
        priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
      }
    }
    else if (cmd == PRIV_SOCK_WRITE_USER_RESP)
    {
      priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str);
      ret = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl);
      priv_sock_send_int(p_sess->ssl_slave_fd, ret);
    }
    else if (cmd == PRIV_SOCK_DO_SSL_HANDSHAKE)
    {
      char result = PRIV_SOCK_RESULT_BAD;
      if (p_sess->data_fd != -1 || p_sess->p_data_ssl != 0)
      {
        bug("state not clean");
      }
      p_sess->data_fd = priv_sock_recv_fd(p_sess->ssl_slave_fd);
      ret = ssl_accept(p_sess, p_sess->data_fd);
      if (ret == 1)
      {
        result = PRIV_SOCK_RESULT_OK;
      }
      else
      {
        vsf_sysutil_close(p_sess->data_fd);
        p_sess->data_fd = -1;
      }
      priv_sock_send_result(p_sess->ssl_slave_fd, result);
    }
    else if (cmd == PRIV_SOCK_DO_SSL_READ)
    {
      str_trunc(&data_str, VSFTP_DATA_BUFSIZE);
      ret = ssl_read_into_str(p_sess, p_sess->p_data_ssl, &data_str);
      priv_sock_send_int(p_sess->ssl_slave_fd, ret);
      priv_sock_send_str(p_sess->ssl_slave_fd, &data_str);
    }
    else if (cmd == PRIV_SOCK_DO_SSL_WRITE)
    {
      priv_sock_get_str(p_sess->ssl_slave_fd, &data_str);
      ret = ssl_write(p_sess->p_data_ssl,
                      str_getbuf(&data_str),
                      str_getlen(&data_str));
      priv_sock_send_int(p_sess->ssl_slave_fd, ret);
    }
    else if (cmd == PRIV_SOCK_DO_SSL_CLOSE)
    {
      char result = PRIV_SOCK_RESULT_BAD;
      if (p_sess->data_fd == -1 && p_sess->p_data_ssl == 0)
      {
        result = PRIV_SOCK_RESULT_OK;
      }
      else
      {
        ret = ssl_data_close(p_sess);
        if (ret == 1)
        {
          result = PRIV_SOCK_RESULT_OK;
        }
        vsf_sysutil_close(p_sess->data_fd);
        p_sess->data_fd = -1;
      }
      priv_sock_send_result(p_sess->ssl_slave_fd, result);
    }
    else
    {
      die("bad request in process_ssl_slave_req");
    }
  }
}