Example #1
0
int
main(int argc, const char* argv[])
{
    struct vsf_session the_session =
    {
        /* Control connection */
        0, 0, 0,
        /* Data connection */
        -1, 0, -1, 0, 0, 0, 0,
        /* Login */
        1, INIT_MYSTR, INIT_MYSTR,
        /* Protocol state */
        0, 1, INIT_MYSTR, 0, 0,
        /* Session state */
        0,
        /* Userids */
        -1, -1, -1,
        /* Pre-chroot() cache */
        INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
        /* Logging */
        -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
        /* Buffers */
        INIT_MYSTR, INIT_MYSTR,
        /* Parent <-> child comms */
        -1, -1,
        /* Number of clients */
        0, 0,
        /* Home directory */
        INIT_MYSTR,
        /* Secure connection state */
        0, 0, 0, 0, 0, 0, -1, -1
    };
    int config_specified = 0;
    const char* p_config_name = VSFTP_DEFAULT_CONFIG;
    /* Zero or one argument supported. If one argument is passed, it is the
     * path to the config file
     */
    if (argc > 2)
    {
        die("vsftpd: too many arguments (I take an optional config file only)");
    }
    else if (argc == 0)
    {
        die("vsftpd: missing argv[0]");
    }
    if (argc == 2)
    {
        if (!vsf_sysutil_strcmp(argv[1], "-v"))
        {
            vsf_exit("vsftpd: version " VSF_VERSION "\n");
        }
        p_config_name = argv[1];
        config_specified = 1;
    }
    /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
     * to be done early (i.e. before config file parse, which may use
     * anonymous pages
     */
    vsf_sysutil_map_anon_pages_init();
    /* Parse config file if it's there */
    {
        struct vsf_sysutil_statbuf* p_statbuf = 0;
        int retval = vsf_sysutil_stat(p_config_name, &p_statbuf);
        if (!vsf_sysutil_retval_is_error(retval))
        {
            vsf_parseconf_load_file(p_config_name, 1);
        }
        else if (config_specified)
        {
            die2("vsftpd: cannot open config file:", p_config_name);
        }
        vsf_sysutil_free(p_statbuf);
    }
    if (!tunable_run_as_launching_user)
    {
        /* Just get out unless we start with requisite privilege */
        die_unless_privileged();
    }
    if (tunable_setproctitle_enable)
    {
        /* Warning -- warning -- may nuke argv, environ */
        vsf_sysutil_setproctitle_init(argc, argv);
    }
    /* Initialize the SSL system here if needed - saves the overhead of each
     *  child doing this itself.
     */
    if (tunable_ssl_enable)
    {
        ssl_init(&the_session);
    }
    if (tunable_listen || tunable_listen_ipv6)
    {
        /* Standalone mode */
        struct vsf_client_launch ret = vsf_standalone_main();
        the_session.num_clients = ret.num_children;
        the_session.num_this_ip = ret.num_this_ip;
    }
    /* Sanity checks - exit with a graceful error message if our STDIN is not
     * a socket. Also check various config options don't collide.
     */
    do_sanity_checks();
    /* Initializes session globals - e.g. IP addr's etc. */
    session_init(&the_session);
    /* Set up "environment", e.g. process group etc. */
    env_init();
    /* Set up logging - must come after global init because we need the remote
     * address to convert into text
     */
    vsf_log_init(&the_session);
    str_alloc_text(&the_session.remote_ip_str,
                   vsf_sysutil_inet_ntop(the_session.p_remote_addr));
    /* Set up options on the command socket */
    vsf_cmdio_sock_setup();
    if (tunable_setproctitle_enable)
    {
        vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
        vsf_sysutil_setproctitle("connected");
    }
    /* We might chroot() very soon (one process model), so we need to open
     * any required config files here.
     */
    if (tunable_tcp_wrappers)
    {
        the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
    }
    {
        const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
        if (p_load_conf)
        {
            vsf_parseconf_load_file(p_load_conf, 1);
        }
    }
    /* SSL may have been enabled by a per-IP configuration.. */
    if (tunable_ssl_enable)
    {
        ssl_init(&the_session);
    }
    if (tunable_deny_email_enable)
    {
        int retval = str_fileread(&the_session.banned_email_str,
                                  tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
        if (vsf_sysutil_retval_is_error(retval))
        {
            die2("cannot open anon e-mail list file:", tunable_banned_email_file);
        }
    }
    if (tunable_banner_file)
    {
        int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
                                  VSFTP_CONF_FILE_MAX);
        if (vsf_sysutil_retval_is_error(retval))
        {
            die2("cannot open banner file:", tunable_banner_file);
        }
    }
    if (tunable_secure_email_list_enable)
    {
        int retval = str_fileread(&the_session.email_passwords_str,
                                  tunable_email_password_file,
                                  VSFTP_CONF_FILE_MAX);
        if (vsf_sysutil_retval_is_error(retval))
        {
            die2("cannot open email passwords file:", tunable_email_password_file);
        }
    }
    /* Special case - can force one process model if we've got a setup
     * needing _no_ privs
     */
    if (!tunable_local_enable && !tunable_connect_from_port_20 &&
            !tunable_chown_uploads)
    {
        tunable_one_process_model = 1;
    }
    if (tunable_run_as_launching_user)
    {
        tunable_one_process_model = 1;
        if (!vsf_sysutil_running_as_root())
        {
            tunable_connect_from_port_20 = 0;
            tunable_chown_uploads = 0;
        }
    }
    if (tunable_one_process_model)
    {
        vsf_one_process_start(&the_session);
    }
    else
    {
        vsf_two_process_start(&the_session);
    }
    /* NOTREACHED */
    bug("should not get here: main");
    return 1;
}
Example #2
0
int
main(int argc, const char* argv[])
{
  struct vsf_session the_session =
  {
    /* Control connection */
    0, 0, 0, 0, 0,
    /* Data connection */
    -1, 0, -1, 0, 0, 0, 0,
    /* Login */
    1, 0, INIT_MYSTR, INIT_MYSTR,
    /* Protocol state */
    0, 1, INIT_MYSTR, 0, 0,
    /* HTTP hacks */
    0, INIT_MYSTR,
    /* Session state */
    0,
    /* Userids */
    -1, -1, -1,
    /* Pre-chroot() cache */
    INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1,
    /* Logging */
    -1, -1, INIT_MYSTR, 0, 0, 0, INIT_MYSTR, 0,
    /* Buffers */
    INIT_MYSTR, INIT_MYSTR, 0, INIT_MYSTR,
    /* Parent <-> child comms */
    -1, -1,
    /* Number of clients */
    0, 0,
    /* Home directory */
    INIT_MYSTR,
    /* Secure connection state */
    0, 0, 0, 0, 0, INIT_MYSTR, 0, -1, -1,
    /* Login fails */
    0,
    /* write_enable */
    0
  };
  int config_loaded = 0;
  int i;
  tunables_load_defaults();
  /* This might need to open /dev/zero on systems lacking MAP_ANON. Needs
   * to be done early (i.e. before config file parse, which may use
   * anonymous pages
   */
  vsf_sysutil_map_anon_pages_init();
  /* Argument parsing. Any argument not starting with "-" is a config file,
   * loaded in the order encountered. -o opt=value options are loading in the
   * order encountered, including correct ordering with respect intermingled
   * config files.
   * If we see -v (version) or an unknown option, parsing bails and exits.
   */
  if (argc == 0)
  {
    die("vsftpd: missing argv[0]");
  }
  for (i = 1; i < argc; ++i)
  {
    const char* p_arg = argv[i];
    if (p_arg[0] != '-')
    {
      config_loaded = 1;
      vsf_parseconf_load_file(p_arg, 1);
    }
    else
    {
      if (p_arg[1] == 'v')
      {
        vsf_exit("vsftpd: version " VSF_VERSION "\n");
      }
      else if (p_arg[1] == 'o')
      {
        vsf_parseconf_load_setting(&p_arg[2], 1);
      }
      else
      {
        die2("unrecognise option: ", p_arg);
      }
    }
  }
  /* Parse default config file if necessary */
  if (!config_loaded) {
    struct vsf_sysutil_statbuf* p_statbuf = 0;
    int retval = vsf_sysutil_stat(VSFTP_DEFAULT_CONFIG, &p_statbuf);
    if (!vsf_sysutil_retval_is_error(retval))
    {
      vsf_parseconf_load_file(VSFTP_DEFAULT_CONFIG, 1);
    }
    vsf_sysutil_free(p_statbuf);
  }
  /* Resolve pasv_address if required */
  if (tunable_pasv_address && tunable_pasv_addr_resolve)
  {
    struct vsf_sysutil_sockaddr* p_addr = 0;
    const char* p_numeric_addr;
    vsf_sysutil_dns_resolve(&p_addr, tunable_pasv_address);
    vsf_sysutil_free((char*) tunable_pasv_address);
    p_numeric_addr = vsf_sysutil_inet_ntop(p_addr);
    tunable_pasv_address = vsf_sysutil_strdup(p_numeric_addr);
    vsf_sysutil_free(p_addr);
  }
  if (!tunable_run_as_launching_user)
  {
    /* Just get out unless we start with requisite privilege */
    die_unless_privileged();
  }
  if (tunable_setproctitle_enable)
  {
    /* Warning -- warning -- may nuke argv, environ */
    vsf_sysutil_setproctitle_init(argc, argv);
  }
  /* Initialize the SSL system here if needed - saves the overhead of each
   * child doing this itself.
   */
  if (tunable_ssl_enable)
  {
    ssl_init(&the_session);
  }
  if (tunable_listen || tunable_listen_ipv6)
  {
    /* Standalone mode */
    struct vsf_client_launch ret = vsf_standalone_main();
    the_session.num_clients = ret.num_children;
    the_session.num_this_ip = ret.num_this_ip;
  }
  if (tunable_tcp_wrappers)
  {
    the_session.tcp_wrapper_ok = vsf_tcp_wrapper_ok(VSFTP_COMMAND_FD);
  }
  {
    const char* p_load_conf = vsf_sysutil_getenv("VSFTPD_LOAD_CONF");
    if (p_load_conf)
    {
      vsf_parseconf_load_file(p_load_conf, 1);
    }
  }
  /* Sanity checks - exit with a graceful error message if our STDIN is not
   * a socket. Also check various config options don't collide.
   */
  do_sanity_checks();
  /* Initializes session globals - e.g. IP addr's etc. */
  session_init(&the_session);
  /* Set up "environment", e.g. process group etc. */
  env_init();
  /* Set up resource limits. */
  limits_init();
  /* Set up logging - must come after global init because we need the remote
   * address to convert into text
   */
  vsf_log_init(&the_session);
  str_alloc_text(&the_session.remote_ip_str,
                 vsf_sysutil_inet_ntop(the_session.p_remote_addr));
  /* Set up options on the command socket */
  vsf_cmdio_sock_setup();
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_set_proctitle_prefix(&the_session.remote_ip_str);
    vsf_sysutil_setproctitle("connected");
  }
  /* We might chroot() very soon (one process model), so we need to open
   * any required config files here.
   */
  /* SSL may have been enabled by a per-IP configuration.. */
  if (tunable_ssl_enable)
  {
    ssl_init(&the_session);
    ssl_add_entropy(&the_session);
  }
  if (tunable_deny_email_enable)
  {
    int retval = -1;
    if (tunable_banned_email_file)
    {
      retval = str_fileread(&the_session.banned_email_str,
                            tunable_banned_email_file, VSFTP_CONF_FILE_MAX);
    }
    if (vsf_sysutil_retval_is_error(retval))
    {
      die2("cannot read anon e-mail list file:", tunable_banned_email_file);
    }
  }
  if (tunable_banner_file)
  {
    int retval = str_fileread(&the_session.banner_str, tunable_banner_file,
                              VSFTP_CONF_FILE_MAX);
    if (vsf_sysutil_retval_is_error(retval))
    {
      die2("cannot read banner file:", tunable_banner_file);
    }
  }
  if (tunable_secure_email_list_enable)
  {
    int retval = -1;
    if (tunable_email_password_file)
    {
      retval = str_fileread(&the_session.email_passwords_str,
                            tunable_email_password_file,
                            VSFTP_CONF_FILE_MAX);
    }
    if (vsf_sysutil_retval_is_error(retval))
    {
      die2("cannot read email passwords file:", tunable_email_password_file);
    }
  }
  if (tunable_run_as_launching_user)
  {
    tunable_one_process_model = 1;
    if (!vsf_sysutil_running_as_root())
    {
      tunable_connect_from_port_20 = 0;
      tunable_chown_uploads = 0;
    }
  }
  if (tunable_one_process_model)
  {
    vsf_one_process_start(&the_session);
  }
  else
  {
    vsf_two_process_start(&the_session);
  }
  /* NOTREACHED */
  bug("should not get here: main");
  return 1;
}
Example #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);
}