Exemplo n.º 1
0
int get_transfer_fd(session_t* sess)
{
	//check have received port or pasv command before
	if(!port_active(sess) && !pasv_active(sess))
	{
		ftp_reply(sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
		return 0;
	}

	int ret = 1;
	if(port_active(sess))
	{
		if(get_port_fd(sess) == 0)
			ret = 0;		
	}

	if(pasv_active(sess))
	{
		if(get_pasv_fd(sess) == 0)
                        ret = 0;
	}

	if(sess->port_addr)
	{
		free(sess->port_addr);
		sess->port_addr = NULL;
	}	

	if(ret) 
		start_data_alarm();

	return ret;
}
Exemplo n.º 2
0
int get_transfer_fd(session_t *pses)
{
    int iret = 0;
    //可能是主动模式,或者被动模式
    //检测是否收到PORT命令或者PASV命令
    if((port_active(pses) < 0) && (pasv_active(pses) < 0))
    {
        ftp_reply(pses->ctrl_fd, FTP_BADSENDCONN, "Use PORT or PASV first.");
        iret = -1;
        return iret;
    }

    //主动模式
    if(port_active(pses) == 0)
    {
        //向nobody进程发送命令
        priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_GET_DATA_SOCK);
        unsigned short port = ntohs(pses->port_addr->sin_port);
        char *ip = inet_ntoa(pses->port_addr->sin_addr);
        //发送port
        priv_sock_send_int(pses->child_fd, (int)port);
        //发送ip
        priv_sock_send_buf(pses->child_fd, ip, strlen(ip));

        //接收应答
        char res = priv_sock_get_result(pses->child_fd);
        if(res == PRIV_SOCK_RESULT_BAD)
        {
            iret = -1;
        }
        else if(res == PRIV_SOCK_RESULT_OK)
        {
            //接收文件描述符
            pses->data_fd = priv_sock_recv_fd(pses->child_fd);
        }
    }
    else if(pasv_active(pses) == 0)//被动模式
    {
        //发送命令给nobody进程,完成客户端和服务端的连接
        priv_sock_send_cmd(pses->child_fd, PRIV_SOCK_PASV_ACCEPT);
        //接收nobody进程的应答
        char res = priv_sock_get_result(pses->child_fd);
        if(res == PRIV_SOCK_RESULT_BAD)
        {
            iret = -1;
        }
        else if(res == PRIV_SOCK_RESULT_OK)
        {
            pses->data_fd = priv_sock_recv_fd(pses->child_fd);
        }
    }
    //连接成功后,该内存空间就不需要了
    if(pses->port_addr != NULL)
    {
        free(pses->port_addr);
        pses->port_addr = NULL;
    }
    return iret;
}
Exemplo n.º 3
0
static int
get_remote_transfer_fd(struct vsf_session* p_sess)
{
  int remote_fd;
  if (!pasv_active(p_sess) && !port_active(p_sess))
  {
    bug("neither PORT nor PASV active in get_remote_transfer_fd");
  }
  p_sess->abor_received = 0;
  if (pasv_active(p_sess))
  {
    remote_fd = vsf_ftpdataio_get_pasv_fd(p_sess);
  }
  else
  {
    remote_fd = vsf_ftpdataio_get_port_fd(p_sess);
  }
  return remote_fd;
}
Exemplo n.º 4
0
/**
 *port_active - 检查主动模式是否被激活过
 *@sess:会话结构体
 *激活过返回1,没有激活过返回0
 */
int ftpproto::port_active(session_t* sess)
{//若主动模式被激活过,则有保存对等的地址,port结构体不为空
	if (sess->port_addr != NULL)
	{//主动模式处于激活的状态
		if (pasv_active(sess))//被动模式也处于激活的状态
		{//这种 状况是不允许的
			LCWFTPD_LOG(ERROR,"both port and pasv are active");
		}
		return 1;
	}
	return 0;//没有激活过
}
Exemplo n.º 5
0
int port_active(session_t* sess)
{
	if(sess->port_addr)
	{
		if(pasv_active(sess))
		{
			fprintf(stderr, "both port and pasv are active.");
			exit(EXIT_FAILURE);
		}
		return 1;
	}
	return 0;
}
Exemplo n.º 6
0
/**
 *get_transfer_fd - 创建数据连接,主动用connect,被动用accept
 *@sess:会话结构体
 *成功返回0,失败返回1
 */
int ftpproto::get_transfer_fd(session_t* sess)
{
	//检测是否收到PORT或者PASV命令
	//激活过是1
	if (!port_active(sess) && !pasv_active(sess))//没有被激活过
	{//两个都没有被激活过,要给个应答,若直接返回会使客户端阻塞
		ftp_reply(sess,FTP_BADSENDCONN,"Use PORT or PASV first.");
		return 1;//失败
	}
	int ret = 0;
	if (port_active(sess))//主动模式,服务器创建数据套接字(bind 20端口)
	{	//调用connect连接客户端IP与端口,建立数据连接
	   if (get_port_fd(sess))//获取主动模式的套接字
	   {//失败
	   	   ret = 1;
	   }   	
	}

	if (pasv_active(sess))//被动模式,使用accept
	{
		if (get_pasv_fd(sess))//获取被动模式的套接字
	   {//失败
	   	   ret = 1;
	   }   	
	}

    if (sess->port_addr)
	{//之前调用过do_port了,数据连接用完就free
		free(sess->port_addr);
		sess->port_addr = NULL;
	}
	// if (ret)
	// {
	// 	//成功创建数据通道后就开启闹钟信号
	// 	start_data_alarm();//重新安装SIGALRM信号,并启动闹钟
	// }
	return ret;//成功是0,失败是1
}
Exemplo n.º 7
0
static int
port_active(struct vsf_session* p_sess)
{
  int ret = 0;
  if (p_sess->p_port_sockaddr != 0)
  {
    ret = 1;
    if (pasv_active(p_sess))
    {
      bug("port and pasv both active");
    }
  }
  return ret;
}
Exemplo n.º 8
0
int port_active(session_t *pses)
{
    if(pses->port_addr != NULL)
    {
        if(pasv_active(pses) == 0)  //主被动模式不能同时处于激活状态
        {
            handle_error_str("both port and pasv are active.");
        }
        return 0;
    }
    else
    {
        return -1;
    }
}
Exemplo n.º 9
0
static void
handle_upload_common(struct vsf_session* p_sess, int is_append)
{
  struct vsf_transfer_ret trans_ret;
  int new_file_fd;
  int remote_fd;
  int retval;
  filesize_t offset = p_sess->restart_pos;
  p_sess->restart_pos = 0;
  if (!pasv_active(p_sess) && !port_active(p_sess))
  {
    vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
    return;
  }
  /* NOTE - actual file permissions will be governed by the tunable umask */
  /* XXX - do we care about race between create and chown() of anonymous
   * upload?
   */
  if (p_sess->is_anonymous && !tunable_anon_other_write_enable)
  {
    new_file_fd = str_create(&p_sess->ftp_arg_str);
  }
  else
  {
    /* For non-anonymous, allow open() to overwrite or append existing files */
    if (!is_append && offset == 0)
    {
      new_file_fd = str_create_overwrite(&p_sess->ftp_arg_str);
    }
    else
    {
      new_file_fd = str_create_append(&p_sess->ftp_arg_str);
    }
  }
  if (vsf_sysutil_retval_is_error(new_file_fd))
  {
    vsf_cmdio_write(p_sess, FTP_UPLOADFAIL, "Could not create file.");
    return;
  }
  /* Are we required to chown() this file for security? */
  if (p_sess->is_anonymous && tunable_chown_uploads)
  {
    if (tunable_one_process_model)
    {
      vsf_one_process_chown_upload(p_sess, new_file_fd);
    }
    else
    {
      vsf_two_process_chown_upload(p_sess, new_file_fd);
    }
  }
  if (!is_append && offset != 0)
  {
    /* XXX - warning, allows seek past end of file! Check for seek > size? */
    vsf_sysutil_lseek_to(new_file_fd, offset);
  }
  remote_fd = get_remote_transfer_fd(p_sess);
  if (vsf_sysutil_retval_is_error(remote_fd))
  {
    goto port_pasv_cleanup_out;
  }
  vsf_cmdio_write(p_sess, FTP_DATACONN,
                  "Ok to send data.");
  vsf_log_start_entry(p_sess, kVSFLogEntryUpload);
  str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  prepend_path_to_filename(&p_sess->log_str);
  if (tunable_ascii_upload_enable && p_sess->is_ascii)
  {
    trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
                                            new_file_fd, 1, 1);
  }
  else
  {
    trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
                                            new_file_fd, 1, 0);
  }
  p_sess->transfer_size = trans_ret.transferred;
  /* XXX - handle failure, delete file? */
  retval = dispose_remote_transfer_fd(p_sess);
  /* Log _after_ the blocking dispose call, so we get transfer times right */
  if (trans_ret.retval == 0 && retval == 0)
  {
    vsf_log_do_log(p_sess, 1);
  }
  else
  {
    vsf_log_do_log(p_sess, 0);
  }
port_pasv_cleanup_out:
  port_cleanup(p_sess);
  pasv_cleanup(p_sess);
  vsf_sysutil_close(new_file_fd);
}
Exemplo n.º 10
0
static void
handle_dir_common(struct vsf_session* p_sess, int full_details)
{
  static struct mystr s_option_str;
  static struct mystr s_filter_str;
  static struct mystr s_dir_name_str;
  static struct vsf_sysutil_statbuf* s_p_dirstat;
  int remote_fd;
  int dir_allow_read = 1;
  struct vsf_sysutil_dir* p_dir = 0;
  str_empty(&s_option_str);
  str_empty(&s_filter_str);
  /* By default open the current directory */
  str_alloc_text(&s_dir_name_str, ".");
  if (!pasv_active(p_sess) && !port_active(p_sess))
  {
    vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
    return;
  }
  /* Do we have an option? Going to be strict here - the option must come
   * first. e.g. "ls -a .." fine, "ls .. -a" not fine
   */
  if (!str_isempty(&p_sess->ftp_arg_str) &&
      str_get_char_at(&p_sess->ftp_arg_str, 0) == '-')
  {
    /* Chop off the '-' */
    str_mid_to_end(&p_sess->ftp_arg_str, &s_option_str, 1);
    /* A space will separate options from filter (if any) */
    str_split_char(&s_option_str, &s_filter_str, ' ');
  }
  else
  {
    /* The argument, if any, is just a filter */
    str_copy(&s_filter_str, &p_sess->ftp_arg_str);
  }
  if (!str_isempty(&s_filter_str))
  {
    /* First check - is it an outright directory, as in "ls /pub" */
    p_dir = str_opendir(&s_filter_str);
    if (p_dir != 0)
    {
      /* Listing a directory! */
      str_copy(&s_dir_name_str, &s_filter_str);
      str_free(&s_filter_str);
    }
    else
    {
      struct str_locate_result locate_result =
        str_locate_char(&s_filter_str, '/');
      if (locate_result.found)
      {
        /* Includes a path! Reverse scan for / in the arg, to get the
         * base directory and filter (if any)
         */
        str_copy(&s_dir_name_str, &s_filter_str);
        str_split_char_reverse(&s_dir_name_str, &s_filter_str, '/');
        /* If we have e.g. "ls /.message", we just ripped off the leading
         * slash because it is the only one!
         */
        if (str_isempty(&s_dir_name_str))
        {
          str_alloc_text(&s_dir_name_str, "/");
        }
      }
    }
  }
  if (p_dir == 0)
  {
    /* NOTE - failure check done below, it's not forgotten */
    p_dir = str_opendir(&s_dir_name_str);
  }
  /* Fine, do it */
  remote_fd = get_remote_transfer_fd(p_sess);
  if (vsf_sysutil_retval_is_error(remote_fd))
  {
    goto dir_close_out;
  }
  vsf_cmdio_write(p_sess, FTP_DATACONN, "Here comes the directory listing.");
  if (p_sess->is_anonymous && p_dir && tunable_anon_world_readable_only)
  {
    vsf_sysutil_dir_stat(p_dir, &s_p_dirstat);
    if (!vsf_sysutil_statbuf_is_readable_other(s_p_dirstat))
    {
      dir_allow_read = 0;
    }
  }
  if (p_dir == 0 || !dir_allow_read)
  {
    vsf_cmdio_write(p_sess, FTP_TRANSFEROK,
                    "Transfer done (but failed to open directory).");
  }
  else
  {
    (void) vsf_ftpdataio_transfer_dir(p_sess, remote_fd, p_dir,
                                      &s_dir_name_str, &s_option_str,
                                      &s_filter_str, full_details);
  }
  (void) dispose_remote_transfer_fd(p_sess);
dir_close_out:
  if (p_dir)
  {
    vsf_sysutil_closedir(p_dir);
  }
  port_cleanup(p_sess);
  pasv_cleanup(p_sess);
}
Exemplo n.º 11
0
static void
handle_retr(struct vsf_session* p_sess)
{
  static struct mystr s_mark_str;
  static struct vsf_sysutil_statbuf* s_p_statbuf;
  struct vsf_transfer_ret trans_ret;
  int retval;
  int remote_fd;
  int opened_file;
  int is_ascii = 0;
  filesize_t offset = p_sess->restart_pos;
  p_sess->restart_pos = 0;
  if (!pasv_active(p_sess) && !port_active(p_sess))
  {
    vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Use PORT or PASV first.");
    return;
  }
  if (p_sess->is_ascii && offset != 0)
  {
    vsf_cmdio_write(p_sess, FTP_FILEFAIL,
                    "No support for resume of ASCII transfer.");
    return;
  }
  opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
  if (vsf_sysutil_retval_is_error(opened_file))
  {
    vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
    return;
  }
  vsf_sysutil_fstat(opened_file, &s_p_statbuf);
  /* No games please */
  if (!vsf_sysutil_statbuf_is_regfile(s_p_statbuf))
  {
    /* Note - pretend open failed */
    vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
    goto file_close_out;
  }
  /* Optionally, we'll be paranoid and only serve publicly readable stuff */
  if (p_sess->is_anonymous && tunable_anon_world_readable_only &&
      !vsf_sysutil_statbuf_is_readable_other(s_p_statbuf))
  {
    vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
    goto file_close_out;
  }
  /* Set the download offset (from REST) if any */
  if (offset != 0)
  {
    vsf_sysutil_lseek_to(opened_file, offset);
  }
  remote_fd = get_remote_transfer_fd(p_sess);
  if (vsf_sysutil_retval_is_error(remote_fd))
  {
    goto port_pasv_cleanup_out;
  }
  vsf_log_start_entry(p_sess, kVSFLogEntryDownload);
  str_copy(&p_sess->log_str, &p_sess->ftp_arg_str);
  prepend_path_to_filename(&p_sess->log_str);
  str_alloc_text(&s_mark_str, "Opening ");
  if (tunable_ascii_download_enable && p_sess->is_ascii)
  {
    str_append_text(&s_mark_str, "ASCII");
    is_ascii = 1;
  }
  else
  {
    str_append_text(&s_mark_str, "BINARY");
  }
  str_append_text(&s_mark_str, " mode data connection for ");
  str_append_str(&s_mark_str, &p_sess->ftp_arg_str);
  str_append_text(&s_mark_str, " (");
  str_append_filesize_t(&s_mark_str,
                        vsf_sysutil_statbuf_get_size(s_p_statbuf));
  str_append_text(&s_mark_str, " bytes).");
  vsf_cmdio_write_str(p_sess, FTP_DATACONN, &s_mark_str);
  trans_ret = vsf_ftpdataio_transfer_file(p_sess, remote_fd,
                                          opened_file, 0, is_ascii);
  p_sess->transfer_size = trans_ret.transferred;
  retval = dispose_remote_transfer_fd(p_sess);
  /* Log _after_ the blocking dispose call, so we get transfer times right */
  if (trans_ret.retval == 0 && retval == 0)
  {
    vsf_log_do_log(p_sess, 1);
  }
  else
  {
    vsf_log_do_log(p_sess, 0);
  }
port_pasv_cleanup_out:
  port_cleanup(p_sess);
  pasv_cleanup(p_sess);
file_close_out:
  vsf_sysutil_close(opened_file);
}