Пример #1
0
static void
handle_eprt(struct vsf_session* p_sess)
{
  static struct mystr s_part1_str;
  static struct mystr s_part2_str;
  int proto;
  int port;
  const unsigned char* p_raw_addr;
  int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  port_cleanup(p_sess);
  pasv_cleanup(p_sess);
  str_copy(&s_part1_str, &p_sess->ftp_arg_str);
  str_split_char(&s_part1_str, &s_part2_str, '|');
  if (!str_isempty(&s_part1_str))
  {
    goto bad_eprt;
  }
  /* Split out the protocol and check it */
  str_split_char(&s_part2_str, &s_part1_str, '|');
  proto = str_atoi(&s_part2_str);
  if (!is_ipv6 || proto != 2)
  {
    vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT protocol.");
    return;
  }
  /* Split out address and parse it */
  str_split_char(&s_part1_str, &s_part2_str, '|');
  p_raw_addr = vsf_sysutil_parse_ipv6(&s_part1_str);
  if (!p_raw_addr)
  {
    goto bad_eprt;
  }
  /* Split out port and parse it */
  str_split_char(&s_part2_str, &s_part1_str, '|');
  if (!str_isempty(&s_part1_str) || str_isempty(&s_part2_str))
  {
    goto bad_eprt;
  }
  port = str_atoi(&s_part2_str);
  if (port < 0 || port > 65535)
  {
    goto bad_eprt;
  }
  vsf_sysutil_sockaddr_alloc_ipv6(&p_sess->p_port_sockaddr);
  vsf_sysutil_sockaddr_set_ipv6addr(p_sess->p_port_sockaddr, p_raw_addr);
  vsf_sysutil_sockaddr_set_port(p_sess->p_port_sockaddr, (unsigned short)port);
  /* SECURITY:
   * 1) Reject requests not connecting to the control socket IP
   * 2) Reject connects to privileged ports
   */
  if (!tunable_port_promiscuous)
  {
    if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr,
                                         p_sess->p_port_sockaddr) ||
        vsf_sysutil_is_port_reserved(port))
    {
      vsf_cmdio_write(p_sess, FTP_BADCMD, "Illegal EPRT command.");
      port_cleanup(p_sess);
      return;
    }
  }
  vsf_cmdio_write(p_sess, FTP_EPRTOK,
                  "EPRT command successful. Consider using EPSV.");
  return;
bad_eprt:
  vsf_cmdio_write(p_sess, FTP_BADCMD, "Bad EPRT command.");
}
Пример #2
0
static void
handle_pasv(struct vsf_session* p_sess, int is_epsv)
{
  static struct mystr s_pasv_res_str;
  static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  int bind_retries = 10;
  unsigned short the_port = 0;
  int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  if (is_epsv && !str_isempty(&p_sess->ftp_arg_str))
  {
    int argval;
    str_upper(&p_sess->ftp_arg_str);
    if (str_equal_text(&p_sess->ftp_arg_str, "ALL"))
    {
      p_sess->epsv_all = 1;
      vsf_cmdio_write(p_sess, FTP_EPSVALLOK, "EPSV ALL ok.");
      return;
    }
    argval = vsf_sysutil_atoi(str_getbuf(&p_sess->ftp_arg_str));
    if (!is_ipv6 || argval != 2)
    {
      vsf_cmdio_write(p_sess, FTP_EPSVBAD, "Bad network protocol.");
      return;
    }
  }
  pasv_cleanup(p_sess);
  port_cleanup(p_sess);
  if (is_epsv && is_ipv6)
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock();
  }
  else
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  }
  vsf_sysutil_activate_reuseaddr(p_sess->pasv_listen_fd);
  while (--bind_retries)
  {
    int retval;
    double scaled_port;
    /* IPPORT_RESERVED */
    unsigned short min_port = 1024;
    unsigned short max_port = 65535;
    if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port)
    {
      min_port = tunable_pasv_min_port;
    }
    if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port)
    {
      max_port = tunable_pasv_max_port;
    }
    the_port = vsf_sysutil_get_random_byte();
    the_port <<= 8;
    the_port |= vsf_sysutil_get_random_byte();
    scaled_port = (double) min_port;
    scaled_port += ((double) the_port / (double) 65536) *
                   ((double) max_port - min_port + 1);
    the_port = (unsigned short) scaled_port;
    vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
    vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port);
    retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr);
    if (!vsf_sysutil_retval_is_error(retval))
    {
      break;
    }
    if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE)
    {
      continue;
    }
    die("vsf_sysutil_bind");
  }
  if (!bind_retries)
  {
    die("vsf_sysutil_bind");
  }
  vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
  if (is_epsv)
  {
    str_alloc_text(&s_pasv_res_str, "Entering Extended Passive Mode (|||");
    str_append_ulong(&s_pasv_res_str, (unsigned long) the_port);
    str_append_text(&s_pasv_res_str, "|)");
    vsf_cmdio_write_str(p_sess, FTP_EPSVOK, &s_pasv_res_str);
    return;
  }
  if (tunable_pasv_address != 0)
  {
    /* Report passive address as specified in configuration */
    if (vsf_sysutil_inet_aton(tunable_pasv_address, s_p_sockaddr) == 0)
    {
      die("invalid pasv_address");
    }
  }
  str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  if (!is_ipv6)
  {
    str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntop(s_p_sockaddr));
  }
  else
  {
    const void* p_v4addr = vsf_sysutil_sockaddr_ipv6_v4(s_p_sockaddr);
    if (p_v4addr)
    {
      str_append_text(&s_pasv_res_str, vsf_sysutil_inet_ntoa(p_v4addr));
    }
  }
  str_replace_char(&s_pasv_res_str, '.', ',');
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, the_port >> 8);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, the_port & 255);
  str_append_text(&s_pasv_res_str, ")");
  vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
}
Пример #3
0
unsigned short
vsf_privop_pasv_listen(struct vsf_session* p_sess)
{
  static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  int bind_retries = 10;
  unsigned short the_port = 0;
  /* IPPORT_RESERVED */
  unsigned short min_port = 1024;
  unsigned short max_port = 65535;
  int is_ipv6 = vsf_sysutil_sockaddr_is_ipv6(p_sess->p_local_addr);
  if (is_ipv6)
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv6_sock();
  }
  else
  {
    p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  }
  vsf_sysutil_activate_reuseaddr(p_sess->pasv_listen_fd);

  if (tunable_pasv_min_port > min_port && tunable_pasv_min_port <= max_port)
  {
    min_port = tunable_pasv_min_port;
  }
  if (tunable_pasv_max_port >= min_port && tunable_pasv_max_port < max_port)
  {
    max_port = tunable_pasv_max_port;
  }

  while (--bind_retries)
  {
    int retval;
    double scaled_port;
    the_port = vsf_sysutil_get_random_byte();
    the_port <<= 8;
    the_port |= vsf_sysutil_get_random_byte();
    scaled_port = (double) min_port;
    scaled_port += ((double) the_port / (double) 65536) *
                   ((double) max_port - min_port + 1);
    the_port = (unsigned short) scaled_port;
    vsf_sysutil_sockaddr_clone(&s_p_sockaddr, p_sess->p_local_addr);
    vsf_sysutil_sockaddr_set_port(s_p_sockaddr, the_port);
    retval = vsf_sysutil_bind(p_sess->pasv_listen_fd, s_p_sockaddr);
    if (!vsf_sysutil_retval_is_error(retval))
    {
      retval = vsf_sysutil_listen(p_sess->pasv_listen_fd, 1);
      if (!vsf_sysutil_retval_is_error(retval))
      {
        break;
      }
    }
    /* SELinux systems can give you an inopportune EACCES, it seems. */
    if (vsf_sysutil_get_error() == kVSFSysUtilErrADDRINUSE ||
        vsf_sysutil_get_error() == kVSFSysUtilErrACCES)
    {
      continue;
    }
    die("vsf_sysutil_bind / listen");
  }
  if (!bind_retries)
  {
    die("vsf_sysutil_bind");
  }
  return the_port;
}