Exemplo n.º 1
0
int
ssl_handshake(struct vsf_session* p_sess, int fd)
{
  /* SECURITY: data SSL connections don't have any auth on them as part of the
   * protocol. If a client sends an unfortunately optional client cert then
   * we can check for a match between the control and data connections.
   */
  SSL* p_ssl;
  int reused;
  if (p_sess->p_data_ssl != NULL)
  {
    die("p_data_ssl should be NULL.");
  }
  /* Initiate the SSL connection by either calling accept or connect */
  p_ssl = get_ssl(p_sess, fd);
  if (p_ssl == NULL)
  {
    return 0;
  }
  p_sess->p_data_ssl = p_ssl;
  setup_bio_callbacks(p_ssl);
  reused = SSL_session_reused(p_ssl);
  if (tunable_require_ssl_reuse && !reused)
  {
    str_alloc_text(&debug_str, "No SSL session reuse on data channel.");
    vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
    ssl_data_close(p_sess);
    return 0;
  }
  if (str_getlen(&p_sess->control_cert_digest) > 0)
  {
    static struct mystr data_cert_digest;
    if (!ssl_cert_digest(p_ssl, p_sess, &data_cert_digest))
    {
      str_alloc_text(&debug_str, "Missing cert on data channel.");
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
      ssl_data_close(p_sess);
      return 0;
    }
    if (str_strcmp(&p_sess->control_cert_digest, &data_cert_digest))
    {
      str_alloc_text(&debug_str, "DIFFERENT cert on data channel.");
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
      ssl_data_close(p_sess);
      return 0;
    }
    if (tunable_debug_ssl)
    {
      str_alloc_text(&debug_str, "Matching cert on data channel.");
      vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str);
    }
  }
  return 1;
}
Exemplo n.º 2
0
void
vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess)
{
  int retval;
  if (p_sess->data_fd == -1)
  {
    bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd");
  }
  /* Reset the data connection alarm so it runs anew with the blocking close */
  start_data_alarm(p_sess);
  vsf_sysutil_uninstall_io_handler();
  if (p_sess->p_data_ssl != 0)
  {
    ssl_data_close(p_sess);
  }
  /* This close() blocks because we set SO_LINGER */
  retval = vsf_sysutil_close_failok(p_sess->data_fd);
  if (vsf_sysutil_retval_is_error(retval))
  {
    /* Do it again without blocking. */
    vsf_sysutil_deactivate_linger_failok(p_sess->data_fd);
    (void) vsf_sysutil_close_failok(p_sess->data_fd);
  }
  vsf_sysutil_clear_alarm();
  p_sess->data_fd = -1;
}
Exemplo n.º 3
0
static int mailstream_low_ssl_close(mailstream_low * s)
{
  struct mailstream_ssl_data * ssl_data;

  ssl_data = (struct mailstream_ssl_data *) s->data;
  ssl_data_close(ssl_data);

  return 0;
}
Exemplo n.º 4
0
int
vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess)
{
  int dispose_ret = 1;
  int retval;
  if (p_sess->data_fd == -1)
  {
    bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd");
  }
  vsf_sysutil_uninstall_io_handler();
  if (p_sess->data_use_ssl && p_sess->ssl_slave_active)
  {
    char result;
    start_data_alarm(p_sess);
    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_CLOSE);
    result = priv_sock_get_result(p_sess->ssl_consumer_fd);
    if (result != PRIV_SOCK_RESULT_OK)
    {
      dispose_ret = 0;
    }
  }
  else if (p_sess->p_data_ssl)
  {
    start_data_alarm(p_sess);
    dispose_ret = ssl_data_close(p_sess);
  }
  if (!p_sess->abor_received && !p_sess->data_timeout && dispose_ret == 1)
  {
    /* If we didn't get a failure, linger on the close() in order to get more
     * accurate transfer times.
     */
    start_data_alarm(p_sess);
    vsf_sysutil_activate_linger(p_sess->data_fd);
  }
  /* This close() blocks because we set SO_LINGER */
  retval = vsf_sysutil_close_failok(p_sess->data_fd);
  if (vsf_sysutil_retval_is_error(retval))
  {
    /* Do it again without blocking. */
    vsf_sysutil_deactivate_linger_failok(p_sess->data_fd);
    (void) vsf_sysutil_close_failok(p_sess->data_fd);
  }
  p_sess->data_fd = -1;
  if (tunable_data_connection_timeout > 0)
  {
    vsf_sysutil_clear_alarm();
  }
  if (p_sess->abor_received || p_sess->data_timeout)
  {
    dispose_ret = 0;
  }
  return dispose_ret;
}
Exemplo n.º 5
0
int
vsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess)
{
  int dispose_ret = 1;
  int retval;
  if (p_sess->data_fd == -1)
  {
    bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd");
  }
  /* Reset the data connection alarm so it runs anew with the blocking close */
  start_data_alarm(p_sess);
  vsf_sysutil_uninstall_io_handler();
  if (p_sess->data_use_ssl && p_sess->ssl_slave_active)
  {
    char result;
    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_CLOSE);
    result = priv_sock_get_result(p_sess->ssl_consumer_fd);
    if (result != PRIV_SOCK_RESULT_OK)
    {
      dispose_ret = 0;
    }
  }
  else if (p_sess->p_data_ssl)
  {
    dispose_ret = ssl_data_close(p_sess);
  }
  /* This close() blocks because we set SO_LINGER */
  retval = vsf_sysutil_close_failok(p_sess->data_fd);
  if (vsf_sysutil_retval_is_error(retval))
  {
    /* Do it again without blocking. */
    vsf_sysutil_deactivate_linger_failok(p_sess->data_fd);
    (void) vsf_sysutil_close_failok(p_sess->data_fd);
  }
  if (tunable_data_connection_timeout > 0)
  {
    vsf_sysutil_clear_alarm();
  }
  p_sess->data_fd = -1;
  return dispose_ret;
}
Exemplo n.º 6
0
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");
    }
  }
}