Ejemplo n.º 1
0
int
vsf_privop_get_ftp_port_sock(struct vsf_session* p_sess,
                             unsigned short remote_port,
                             int use_port_sockaddr)
{
  static struct vsf_sysutil_sockaddr* p_sockaddr;
  const struct vsf_sysutil_sockaddr* p_connect_to;
  int retval;
  int i;
  int s = vsf_sysutil_get_ipsock(p_sess->p_local_addr);
  int port = 0;
  if (vsf_sysutil_is_port_reserved(remote_port))
  {
    die("Illegal port request");
  }
  if (tunable_connect_from_port_20)
  {
    port = tunable_ftp_data_port;
  }
  vsf_sysutil_activate_reuseaddr(s);
  /* A report of failure here on Solaris, presumably buggy address reuse
   * support? We'll retry.
   */
  for (i = 0; i < 2; ++i)
  {
    double sleep_for;
    vsf_sysutil_sockaddr_clone(&p_sockaddr, p_sess->p_local_addr);
    vsf_sysutil_sockaddr_set_port(p_sockaddr, port);
    retval = vsf_sysutil_bind(s, p_sockaddr);
    if (retval == 0)
    {
      break;
    }
    if (vsf_sysutil_get_error() != kVSFSysUtilErrADDRINUSE || i == 1)
    {
      die("vsf_sysutil_bind");
    }
    sleep_for = vsf_sysutil_get_random_byte();
    sleep_for /= 256.0;
    sleep_for += 1.0;
    vsf_sysutil_sleep(sleep_for);
  }
  if (use_port_sockaddr)
  {
    p_connect_to = p_sess->p_port_sockaddr;
  }
  else
  {
    vsf_sysutil_sockaddr_set_port(p_sess->p_remote_addr, remote_port);
    p_connect_to = p_sess->p_remote_addr;
  }
  retval = vsf_sysutil_connect_timeout(s, p_connect_to,
                                       tunable_connect_timeout);
  if (vsf_sysutil_retval_is_error(retval))
  {
    vsf_sysutil_close(s);
    s = -1;
  }
  return s;
}
Ejemplo n.º 2
0
static void
handle_pasv(struct vsf_session* p_sess)
{
  static struct mystr s_pasv_res_str;
  static struct vsf_sysutil_sockaddr* s_p_sockaddr;
  struct vsf_sysutil_ipv4port listen_port;
  struct vsf_sysutil_ipv4addr listen_ipaddr;
  int bind_retries = 10;
  pasv_cleanup(p_sess);
  port_cleanup(p_sess);
  p_sess->pasv_listen_fd = vsf_sysutil_get_ipv4_sock();
  while (--bind_retries)
  {
    int retval;
    unsigned short the_port;
    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) 65535) *
                   ((double) max_port - min_port);
    the_port = (unsigned short) scaled_port;
    vsf_sysutil_sockaddr_alloc_ipv4(&s_p_sockaddr);
    vsf_sysutil_sockaddr_set_port(s_p_sockaddr,
                                  vsf_sysutil_ipv4port_from_int(the_port));
    /* Bind to same address we got the incoming connect on */
    vsf_sysutil_sockaddr_set_ipaddr(s_p_sockaddr,
      vsf_sysutil_sockaddr_get_ipaddr(p_sess->p_local_addr));
    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);
  /* Get the address of the bound socket, for the port */
  vsf_sysutil_getsockname(p_sess->pasv_listen_fd, &s_p_sockaddr);
  if (tunable_pasv_address != 0)
  {
    /* Report passive address as specified in configuration */
    if (vsf_sysutil_inet_aton(tunable_pasv_address, &listen_ipaddr) == 0)
    {
      die("invalid pasv_address");
    }
  }
  else
  {
    /* Use address of bound socket for passive address */
    listen_ipaddr = vsf_sysutil_sockaddr_get_ipaddr(s_p_sockaddr);
  }
  listen_port = vsf_sysutil_sockaddr_get_port(s_p_sockaddr);
  str_alloc_text(&s_pasv_res_str, "Entering Passive Mode (");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[0]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[1]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[2]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_ipaddr.data[3]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_port.data[0]);
  str_append_text(&s_pasv_res_str, ",");
  str_append_ulong(&s_pasv_res_str, listen_port.data[1]);
  str_append_text(&s_pasv_res_str, ")");
  vsf_cmdio_write_str(p_sess, FTP_PASVOK, &s_pasv_res_str);
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
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;
}