예제 #1
0
파일: prelogin.c 프로젝트: AllardJ/Tomato
void
init_connection(struct vsf_session* p_sess)
{
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("not logged in");
  }
  /* Before we talk to the remote, make sure an alarm is set up in case
   * writing the initial greetings should block.
   */
  vsf_cmdio_set_alarm(p_sess);
  /* Check limits before doing an implicit SSL handshake, to avoid DoS
   * attacks. This will result in plain text messages being sent to the SSL
   * client, but we can live with that.
   */
  check_limits(p_sess);
  if (tunable_ssl_enable && tunable_implicit_ssl)
  {
    ssl_control_handshake(p_sess);
  }
  if (tunable_ftp_enable)
  {
    emit_greeting(p_sess);
  }
  parse_username_password(p_sess);
}
예제 #2
0
파일: prelogin.c 프로젝트: fithisux/vsftpdx
void
init_connection(struct vsf_session* p_sess)
{
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("not logged in");
  }
  
  #ifdef VSF_BUILD_SQLITE
  /* In stealth mode we wont answer the connection unless the remote host
   * is known to our database.
   */
  if (tunable_sqlite_enable && tunable_stealth_mode)
  {
    int retval = vsf_db_check_remote_host(&p_sess->remote_ip_str);
    if (retval == 0)
    {
      /* The IP check failed we drop the connection silently. */
      vsf_sysutil_shutdown_read_failok(VSFTP_COMMAND_FD);
      vsf_sysutil_exit(0);        
    }
  }
  #endif
    
  /* Before we talk to the remote, make sure an alarm is set up in case
   * writing the initial greetings should block.
   */
  vsf_cmdio_set_alarm(p_sess);
  emit_greeting(p_sess);
  parse_username_password(p_sess);
}
예제 #3
0
void
init_connection(struct vsf_session* p_sess)
{
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("not logged in");
  }
  /* Before we talk to the remote, make sure an alarm is set up in case
   * writing the initial greetings should block.
   */
  vsf_cmdio_set_alarm(p_sess);
  emit_greeting(p_sess);
  parse_username_password(p_sess);
}
예제 #4
0
void
init_connection(struct vsf_session* p_sess)
{
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("not logged in");
  }
  /* Before we talk to the remote, make sure an alarm is set up in case
   * writing the initial greetings should block.
   */
  vsf_cmdio_set_alarm(p_sess);
  /* Kitsune, prevent printing greeting if just updated */  
  if (!kitsune_is_updating()) {  
    emit_greeting(p_sess);
  }
  parse_username_password(p_sess);
}
예제 #5
0
void
vsf_two_process_login(struct vsf_session* p_sess,
                      const struct mystr* p_pass_str)
{
  char result;
  priv_sock_send_cmd(p_sess->child_fd, PRIV_SOCK_LOGIN);
  priv_sock_send_str(p_sess->child_fd, &p_sess->user_str);
  priv_sock_send_str(p_sess->child_fd, p_pass_str);
  priv_sock_send_int(p_sess->child_fd, p_sess->control_use_ssl);
  priv_sock_send_int(p_sess->child_fd, p_sess->data_use_ssl);
  result = priv_sock_get_result(p_sess->child_fd);
  if (result == PRIV_SOCK_RESULT_OK)
  {
    /* Miracle. We don't emit the success message here. That is left to
     * process_post_login().
     * Exit normally, unless we are remaining as the SSL read / write child.
     */
    if (!p_sess->control_use_ssl)
    {
      vsf_sysutil_exit(0);
    }
    else
    {
      vsf_sysutil_clear_alarm();
      vsf_sysutil_close(p_sess->child_fd);
      if (tunable_setproctitle_enable)
      {
        vsf_sysutil_setproctitle("SSL handler");
      }
      process_ssl_slave_req(p_sess);
    }
    /* NOTREACHED */
  }
  else if (result == PRIV_SOCK_RESULT_BAD)
  {
    /* Continue the processing loop.. */
    return;
  }
  else
  {
    die("priv_sock_get_result");
  }
}
예제 #6
0
void
process_post_login(struct vsf_session* p_sess)
{
  int retval;

  if (p_sess->is_anonymous)
  {
    vsf_sysutil_set_umask(tunable_anon_umask);
    p_sess->bw_rate_max = tunable_anon_max_rate;
  }
  else
  {
    vsf_sysutil_set_umask(tunable_local_umask);
    p_sess->bw_rate_max = tunable_local_max_rate;
  }
  if (tunable_async_abor_enable)
  {
    vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess);
    vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD);
  }

  /* Kitsune */	
  vsf_sysutil_kitsune_set_update_point("postlogin.c");
  if(!kitsune_is_updating()) {
    /* Handle any login message */
    vsf_banner_dir_changed(p_sess, FTP_LOGINOK);
    vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful. Have fun.");
	} else {
    /* Set sigchld function pointer (normally done in twoprocess.c) */    
    vsf_sysutil_default_sig(kVSFSysUtilSigCHLD);
    vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, twoproc_handle_sigchld);
  }
  /* End Kitsune */

  while(1)
  {
    if (tunable_setproctitle_enable)
    {
      vsf_sysutil_setproctitle("IDLE");
    }

		/* Kitsune update point */
    kitsune_update("postlogin.c");  /**DSU updatepoint */
    
    /* Blocks */
	  vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
	                            &p_sess->ftp_arg_str, 1);
	  if (tunable_setproctitle_enable)
	  {
	    struct mystr proctitle_str = INIT_MYSTR;
	    str_copy(&proctitle_str, &p_sess->ftp_cmd_str);
	    if (!str_isempty(&p_sess->ftp_arg_str))
	    {
	      str_append_char(&proctitle_str, ' ');
	      str_append_str(&proctitle_str, &p_sess->ftp_arg_str);
	    }
	    /* Suggestion from Solar */
	    str_replace_unprintable(&proctitle_str, '?');
	    vsf_sysutil_setproctitle_str(&proctitle_str);
	    str_free(&proctitle_str);
	  }
	  if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
	  {
	    vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye.");
	    vsf_sysutil_exit(0);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "XPWD"))
	  {
	    handle_pwd(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "XCWD"))
	  {
	    handle_cwd(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "XCUP"))
	  {
	    handle_cdup(p_sess);
	  }
	  else if (tunable_pasv_enable &&
	           str_equal_text(&p_sess->ftp_cmd_str, "PASV"))
	  {
	    handle_pasv(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "RETR"))
	  {
	    handle_retr(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP"))
	  {
	    vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok.");
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST"))
	  {
	    vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8");
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP"))
	  {
	    vsf_cmdio_write(p_sess, FTP_BADHELP, "Sorry, I don't have help.");
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "LIST"))
	  {
	    handle_list(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE"))
	  {
	    handle_type(p_sess);
	  }
	  else if (tunable_port_enable &&
	           str_equal_text(&p_sess->ftp_cmd_str, "PORT"))
	  {
	    handle_port(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
	           str_equal_text(&p_sess->ftp_cmd_str, "STOR"))
	  {
	    handle_stor(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) &&
	           (str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
	            str_equal_text(&p_sess->ftp_cmd_str, "XMKD")))
	  {
	    handle_mkd(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
	           (str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
	            str_equal_text(&p_sess->ftp_cmd_str, "XRMD")))
	  {
	    handle_rmd(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
	           str_equal_text(&p_sess->ftp_cmd_str, "DELE"))
	  {
	    handle_dele(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "REST"))
	  {
	    handle_rest(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
	           str_equal_text(&p_sess->ftp_cmd_str, "RNFR"))
	  {
	    handle_rnfr(p_sess);
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
	           str_equal_text(&p_sess->ftp_cmd_str, "RNTO"))
	  {
	    handle_rnto(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "NLST"))
	  {
	    handle_nlst(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE"))
	  {
	    handle_size(p_sess);
	  }
	  else if (!p_sess->is_anonymous &&
	           str_equal_text(&p_sess->ftp_cmd_str, "SITE"))
	  {
	    handle_site(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR"))
	  {
	    vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR.");
	  }
	  else if (tunable_write_enable &&
	           (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
	           str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
	  {
	    handle_appe(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM"))
	  {
	    handle_mdtm(p_sess);
	  }
	  else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "PORT") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "STOR") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "XMKD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "XRMD") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "DELE") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "RNFR") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "RNTO") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "SITE") ||
	           str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
	  {
	    vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
	  }
	  else
	  {
	    vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
	  }
	}

}
예제 #7
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;
}
예제 #8
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;
}
예제 #9
0
/* This delegation is common to all setproctitle() implementations */
void
vsf_sysutil_setproctitle_str(const struct mystr* p_str)
{
  vsf_sysutil_setproctitle(str_getbuf(p_str));
}
예제 #10
0
void
process_post_login(struct vsf_session* p_sess)
{
  if (p_sess->is_anonymous)
  {
    vsf_sysutil_set_umask(tunable_anon_umask);
    p_sess->bw_rate_max = tunable_anon_max_rate;
  }
  else
  {
    vsf_sysutil_set_umask(tunable_local_umask);
    p_sess->bw_rate_max = tunable_local_max_rate;
  }
  if (tunable_async_abor_enable)
  {
    vsf_sysutil_install_sighandler(kVSFSysUtilSigURG, handle_sigurg, p_sess);
    vsf_sysutil_activate_sigurg(VSFTP_COMMAND_FD);
  }
  /* Handle any login message */
  vsf_banner_dir_changed(p_sess, FTP_LOGINOK);
  vsf_cmdio_write(p_sess, FTP_LOGINOK, "Login successful.");
  while(1)
  {
    int cmd_ok = 1;
    if (tunable_setproctitle_enable)
    {
      vsf_sysutil_setproctitle("IDLE");
    }
    /* Blocks */
    vsf_cmdio_get_cmd_and_arg(p_sess, &p_sess->ftp_cmd_str,
                              &p_sess->ftp_arg_str, 1);
    if (tunable_setproctitle_enable)
    {
      struct mystr proctitle_str = INIT_MYSTR;
      str_copy(&proctitle_str, &p_sess->ftp_cmd_str);
      if (!str_isempty(&p_sess->ftp_arg_str))
      {
        str_append_char(&proctitle_str, ' ');
        str_append_str(&proctitle_str, &p_sess->ftp_arg_str);
      }
      /* Suggestion from Solar */
      str_replace_unprintable(&proctitle_str, '?');
      vsf_sysutil_setproctitle_str(&proctitle_str);
      str_free(&proctitle_str);
    }
    /* Test command against the allowed list.. */
    if (tunable_cmds_allowed)
    {
      static struct mystr s_src_str;
      static struct mystr s_rhs_str;
      str_alloc_text(&s_src_str, tunable_cmds_allowed);
      while (1)
      {
        str_split_char(&s_src_str, &s_rhs_str, ',');
        if (str_isempty(&s_src_str))
        {
          cmd_ok = 0;
          break;
        }
        else if (str_equal(&s_src_str, &p_sess->ftp_cmd_str))
        {
          break;
        }
        str_copy(&s_src_str, &s_rhs_str);
      }
    }
    if (!cmd_ok)
    {
      vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "QUIT"))
    {
      vsf_cmdio_write(p_sess, FTP_GOODBYE, "Goodbye.");
      vsf_sysutil_exit(0);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "PWD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "XPWD"))
    {
      handle_pwd(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "XCWD"))
    {
      handle_cwd(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "CDUP") ||
             str_equal_text(&p_sess->ftp_cmd_str, "XCUP"))
    {
      handle_cdup(p_sess);
    }
    else if (tunable_pasv_enable &&
             !p_sess->epsv_all &&
             (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
              str_equal_text(&p_sess->ftp_cmd_str, "P@SW")))
    {
      handle_pasv(p_sess, 0);
    }
    else if (tunable_pasv_enable &&
             str_equal_text(&p_sess->ftp_cmd_str, "EPSV"))
    {
      handle_pasv(p_sess, 1);
    }
    else if (tunable_download_enable &&
             str_equal_text(&p_sess->ftp_cmd_str, "RETR"))
    {
      handle_retr(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "NOOP"))
    {
      vsf_cmdio_write(p_sess, FTP_NOOPOK, "NOOP ok.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "SYST"))
    {
      vsf_cmdio_write(p_sess, FTP_SYSTOK, "UNIX Type: L8");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "HELP"))
    {
      handle_help(p_sess);
    }
    else if (tunable_dirlist_enable &&
             str_equal_text(&p_sess->ftp_cmd_str, "LIST"))
    {
      handle_list(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "TYPE"))
    {
      handle_type(p_sess);
    }
    else if (tunable_port_enable &&
             !p_sess->epsv_all &&
             str_equal_text(&p_sess->ftp_cmd_str, "PORT"))
    {
      handle_port(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_upload_enable || !p_sess->is_anonymous) &&
             str_equal_text(&p_sess->ftp_cmd_str, "STOR"))
    {
      handle_stor(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_mkdir_write_enable || !p_sess->is_anonymous) &&
             (str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
              str_equal_text(&p_sess->ftp_cmd_str, "XMKD")))
    {
      handle_mkd(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
             (str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
              str_equal_text(&p_sess->ftp_cmd_str, "XRMD")))
    {
      handle_rmd(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
             str_equal_text(&p_sess->ftp_cmd_str, "DELE"))
    {
      handle_dele(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "REST"))
    {
      handle_rest(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
             str_equal_text(&p_sess->ftp_cmd_str, "RNFR"))
    {
      handle_rnfr(p_sess);
    }
    else if (tunable_write_enable &&
             (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
             str_equal_text(&p_sess->ftp_cmd_str, "RNTO"))
    {
      handle_rnto(p_sess);
    }
    else if (tunable_dirlist_enable &&
             str_equal_text(&p_sess->ftp_cmd_str, "NLST"))
    {
      handle_nlst(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "SIZE"))
    {
      handle_size(p_sess);
    }
    else if (!p_sess->is_anonymous &&
             str_equal_text(&p_sess->ftp_cmd_str, "SITE"))
    {
      handle_site(p_sess);
    }
    /* Note - the weird ABOR string is checking for an async ABOR arriving
     * without a SIGURG condition.
     */
    else if (str_equal_text(&p_sess->ftp_cmd_str, "ABOR") ||
             str_equal_text(&p_sess->ftp_cmd_str, "\377\364\377\362ABOR"))
    {
      vsf_cmdio_write(p_sess, FTP_ABOR_NOCONN, "No transfer to ABOR.");
    }
    else if (tunable_write_enable &&
             (tunable_anon_other_write_enable || !p_sess->is_anonymous) &&
             str_equal_text(&p_sess->ftp_cmd_str, "APPE"))
    {
      handle_appe(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "MDTM"))
    {
      handle_mdtm(p_sess);
    }
    else if (tunable_port_enable &&
             str_equal_text(&p_sess->ftp_cmd_str, "EPRT"))
    {
      handle_eprt(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "STRU"))
    {
      str_upper(&p_sess->ftp_arg_str);
      if (str_equal_text(&p_sess->ftp_arg_str, "F"))
      {
        vsf_cmdio_write(p_sess, FTP_STRUOK, "Structure set to F.");
      }
      else
      {
        vsf_cmdio_write(p_sess, FTP_BADSTRU, "Bad STRU command.");
      }
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "MODE"))
    {
      str_upper(&p_sess->ftp_arg_str);
      if (str_equal_text(&p_sess->ftp_arg_str, "S"))
      {
        vsf_cmdio_write(p_sess, FTP_MODEOK, "Mode set to S.");
      }
      else
      {
        vsf_cmdio_write(p_sess, FTP_BADMODE, "Bad MODE command.");
      }
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "STOU"))
    {
      handle_stou(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "ALLO"))
    {
      vsf_cmdio_write(p_sess, FTP_ALLOOK, "ALLO command ignored.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "REIN"))
    {
      vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "REIN not implemented.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "ACCT"))
    {
      vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "ACCT not implemented.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "SMNT"))
    {
      vsf_cmdio_write(p_sess, FTP_COMMANDNOTIMPL, "SMNT not implemented.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "FEAT"))
    {
      vsf_cmdio_write_hyphen(p_sess, FTP_FEAT, "Features:");
      vsf_cmdio_write_raw(p_sess, " MDTM\r\n");
      vsf_cmdio_write_raw(p_sess, " REST STREAM\r\n");
      vsf_cmdio_write_raw(p_sess, " SIZE\r\n");
      vsf_cmdio_write(p_sess, FTP_FEAT, "End");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "OPTS"))
    {
      vsf_cmdio_write(p_sess, FTP_BADOPTS, "Option not understood.");
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "STAT") &&
             str_isempty(&p_sess->ftp_arg_str))
    {
      handle_stat(p_sess);
    }
    else if (tunable_dirlist_enable && 
             str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
    {
      handle_stat_file(p_sess);
    }
    else if (str_equal_text(&p_sess->ftp_cmd_str, "PASV") ||
             str_equal_text(&p_sess->ftp_cmd_str, "PORT") ||
             str_equal_text(&p_sess->ftp_cmd_str, "STOR") ||
             str_equal_text(&p_sess->ftp_cmd_str, "MKD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "XMKD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "RMD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "XRMD") ||
             str_equal_text(&p_sess->ftp_cmd_str, "DELE") ||
             str_equal_text(&p_sess->ftp_cmd_str, "RNFR") ||
             str_equal_text(&p_sess->ftp_cmd_str, "RNTO") ||
             str_equal_text(&p_sess->ftp_cmd_str, "SITE") ||
             str_equal_text(&p_sess->ftp_cmd_str, "APPE") ||
             str_equal_text(&p_sess->ftp_cmd_str, "EPSV") ||
             str_equal_text(&p_sess->ftp_cmd_str, "EPRT") ||
             str_equal_text(&p_sess->ftp_cmd_str, "RETR") ||
             str_equal_text(&p_sess->ftp_cmd_str, "LIST") ||
             str_equal_text(&p_sess->ftp_cmd_str, "NLST") ||
             str_equal_text(&p_sess->ftp_cmd_str, "STOU") ||
             str_equal_text(&p_sess->ftp_cmd_str, "ALLO") ||
             str_equal_text(&p_sess->ftp_cmd_str, "REIN") ||
             str_equal_text(&p_sess->ftp_cmd_str, "ACCT") ||
             str_equal_text(&p_sess->ftp_cmd_str, "SMNT") ||
             str_equal_text(&p_sess->ftp_cmd_str, "FEAT") ||
             str_equal_text(&p_sess->ftp_cmd_str, "OPTS") ||
             str_equal_text(&p_sess->ftp_cmd_str, "STAT"))
    {
      vsf_cmdio_write(p_sess, FTP_NOPERM, "Permission denied.");
    }
    else
    {
      vsf_cmdio_write(p_sess, FTP_BADCMD, "Unknown command.");
    }
  }
}
예제 #11
0
struct vsf_client_launch
vsf_standalone_main(void)
{
  struct vsf_sysutil_sockaddr* p_sockaddr = 0;
  struct vsf_sysutil_ipv4addr listen_ipaddr;
  int listen_sock = vsf_sysutil_get_ipv4_sock();
  int retval;
  s_p_ip_count_hash = hash_alloc(256, sizeof(struct vsf_sysutil_ipv4addr),
                                 sizeof(unsigned int), hash_ip);
  s_p_pid_ip_hash = hash_alloc(256, sizeof(int),
                               sizeof(struct vsf_sysutil_ipv4addr), hash_pid);
  if (tunable_setproctitle_enable)
  {
    vsf_sysutil_setproctitle("LISTENER");
  }
  vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0);
  vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup);

  vsf_sysutil_activate_reuseaddr(listen_sock);
  vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr);
  vsf_sysutil_sockaddr_set_port(
      p_sockaddr, vsf_sysutil_ipv4port_from_int(tunable_listen_port));
  if (!tunable_listen_address ||
      vsf_sysutil_inet_aton(tunable_listen_address, &listen_ipaddr) == 0)
  {
    listen_ipaddr = vsf_sysutil_sockaddr_get_any();
  }
  vsf_sysutil_sockaddr_set_ipaddr(p_sockaddr, listen_ipaddr);
  retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
  
  vsf_sysutil_free(p_sockaddr);

  if (vsf_sysutil_retval_is_error(retval))
  {
    die("could not bind listening socket");
  }
  vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);

  while (1)
  {
    struct vsf_client_launch child_info;
    static struct vsf_sysutil_sockaddr* p_accept_addr;
    int new_child;
    struct vsf_sysutil_ipv4addr ip_addr;
    /* NOTE - wake up every 10 seconds to make sure we notice child exit
     * in a timely manner (the sync signal framework race)
     */
    int new_client_sock = vsf_sysutil_accept_timeout(
        listen_sock, &p_accept_addr, 10);
    if (s_reload_needed)
    {
      s_reload_needed = 0;
      do_reload();
    }
    if (vsf_sysutil_retval_is_error(new_client_sock))
    {
      continue;
    }
    ip_addr = vsf_sysutil_sockaddr_get_ipaddr(p_accept_addr);
    ++s_children;
    child_info.num_children = s_children;
    child_info.num_this_ip = handle_ip_count(&ip_addr);
    new_child = vsf_sysutil_fork_failok();
    if (new_child != 0)
    {
      /* Parent context */
      vsf_sysutil_close(new_client_sock);
      if (new_child > 0)
      {
        hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, (void*)&ip_addr);
      }
      else
      {
        /* fork() failed, clear up! */
        --s_children;
        drop_ip_count(&ip_addr);
      }
      /* Fall through to while() loop and accept() again */
    }
    else
    {
      /* Child context */
      vsf_sysutil_close(listen_sock);
      prepare_child(new_client_sock);
      /* By returning here we "launch" the child process with the same
       * contract as xinetd would provide.
       */
      return child_info;
    }
  }
}
예제 #12
0
struct vsf_client_launch
vsf_standalone_main(void)
{
    struct vsf_sysutil_sockaddr* p_accept_addr = 0;
    int listen_sock = -1;
    int retval;
    s_ipaddr_size = vsf_sysutil_get_ipaddr_size();
    if (tunable_listen && tunable_listen_ipv6)
    {
        die("run two copies of vsftpd for IPv4 and IPv6");
    }
    if (tunable_background)
    {
        int forkret = vsf_sysutil_fork();
        if (forkret > 0)
        {
            /* Parent, just exit */
            vsf_sysutil_exit(0);
        }
        vsf_sysutil_make_session_leader();
    }
    if (tunable_listen)
    {
        listen_sock = vsf_sysutil_get_ipv4_sock();
    }
    else
    {
        listen_sock = vsf_sysutil_get_ipv6_sock();
    }
    vsf_sysutil_activate_reuseaddr(listen_sock);

    s_p_ip_count_hash = hash_alloc(256, s_ipaddr_size,
                                   sizeof(unsigned int), hash_ip);
    s_p_pid_ip_hash = hash_alloc(256, sizeof(int),
                                 s_ipaddr_size, hash_pid);
    if (tunable_setproctitle_enable)
    {
        vsf_sysutil_setproctitle("LISTENER");
    }
    vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld);
    vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup);
    if (tunable_listen)
    {
        struct vsf_sysutil_sockaddr* p_sockaddr = 0;
        vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr);
        vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_listen_port);
        if (!tunable_listen_address)
        {
            vsf_sysutil_sockaddr_set_any(p_sockaddr);
        }
        else
        {
            if (!vsf_sysutil_inet_aton(tunable_listen_address, p_sockaddr))
            {
                die2("bad listen_address: ", tunable_listen_address);
            }
        }
        retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
        vsf_sysutil_free(p_sockaddr);
        if (vsf_sysutil_retval_is_error(retval))
        {
            die("could not bind listening IPv4 socket");
        }
    }
    else
    {
        struct vsf_sysutil_sockaddr* p_sockaddr = 0;
        vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr);
        vsf_sysutil_sockaddr_set_port(p_sockaddr, tunable_listen_port);
        if (!tunable_listen_address6)
        {
            vsf_sysutil_sockaddr_set_any(p_sockaddr);
        }
        else
        {
            struct mystr addr_str = INIT_MYSTR;
            const unsigned char* p_raw_addr;
            str_alloc_text(&addr_str, tunable_listen_address6);
            p_raw_addr = vsf_sysutil_parse_ipv6(&addr_str);
            str_free(&addr_str);
            if (!p_raw_addr)
            {
                die2("bad listen_address6: ", tunable_listen_address6);
            }
            vsf_sysutil_sockaddr_set_ipv6addr(p_sockaddr, p_raw_addr);
        }
        retval = vsf_sysutil_bind(listen_sock, p_sockaddr);
        vsf_sysutil_free(p_sockaddr);
        if (vsf_sysutil_retval_is_error(retval))
        {
            die("could not bind listening IPv6 socket");
        }
    }
    vsf_sysutil_listen(listen_sock, VSFTP_LISTEN_BACKLOG);
    vsf_sysutil_sockaddr_alloc(&p_accept_addr);
    while (1)
    {
        struct vsf_client_launch child_info;
        void* p_raw_addr;
        int new_child;
        int new_client_sock;
        vsf_sysutil_unblock_sig(kVSFSysUtilSigCHLD);
        vsf_sysutil_unblock_sig(kVSFSysUtilSigHUP);
        new_client_sock = vsf_sysutil_accept_timeout(
                              listen_sock, p_accept_addr, 0);
        vsf_sysutil_block_sig(kVSFSysUtilSigCHLD);
        vsf_sysutil_block_sig(kVSFSysUtilSigHUP);
        if (vsf_sysutil_retval_is_error(new_client_sock))
        {
            continue;
        }
        ++s_children;
        child_info.num_children = s_children;
        child_info.num_this_ip = 0;
        p_raw_addr = vsf_sysutil_sockaddr_get_raw_addr(p_accept_addr);
        child_info.num_this_ip = handle_ip_count(p_raw_addr);
        new_child = vsf_sysutil_fork_failok();
        if (new_child != 0)
        {
            /* Parent context */
            vsf_sysutil_close(new_client_sock);
            if (new_child > 0)
            {
                hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, p_raw_addr);
            }
            else
            {
                /* fork() failed, clear up! */
                --s_children;
                drop_ip_count(p_raw_addr);
            }
            /* Fall through to while() loop and accept() again */
        }
        else
        {
            /* Child context */
            vsf_sysutil_close(listen_sock);
            prepare_child(new_client_sock);
            /* By returning here we "launch" the child process with the same
             * contract as xinetd would provide.
             */
            return child_info;
        }
    }
}
예제 #13
0
파일: sslslave.c 프로젝트: AllardJ/Tomato
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");
    }
  }
}