Пример #1
0
int
vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess)
{
  int ret = 0;
  if (!p_sess->data_use_ssl)
  {
    return 1;
  }
  if (!p_sess->ssl_slave_active)
  {
    ret = ssl_accept(p_sess, p_sess->data_fd);
  }
  else
  {
    int sock_ret;
    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE);
    priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd);
    sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd);
    if (sock_ret == PRIV_SOCK_RESULT_OK)
    {
      ret = 1;
    }
  }
  if (ret != 1)
  {
    if (tunable_require_ssl_reuse)
    {
      vsf_cmdio_write_exit(p_sess, FTP_DATATLSBAD,
                           "SSL connection failed: session reuse required", 1);
    } else {
      vsf_cmdio_write(p_sess, FTP_DATATLSBAD, "SSL connection failed");
    }
  }
  return ret;
}
Пример #2
0
/** Perform an SSL handshake.
 * In some cases, a handshake may block, so we may have to call this
 * function again. Accordingly, we return state information that
 * tells us if we need to do that.
 * \param ssl pointer to an SSL object.
 * \return resulting state of the object.
 */
int
ssl_handshake(SSL *ssl)
{
  int ret;
  int state = 0;

  if ((ret = SSL_do_handshake(ssl)) <= 0) {
    switch (SSL_get_error(ssl, ret)) {
    case SSL_ERROR_WANT_READ:
      /* We must want for the socket to be readable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_do_handshake wants read");
      state = MYSSL_RB | MYSSL_HANDSHAKE;
      break;
    case SSL_ERROR_WANT_WRITE:
      /* We must want for the socket to be writable, and then repeat
       * the call.
       */
      ssl_debugdump("SSL_do_handshake wants write");
      state = MYSSL_WB | MYSSL_HANDSHAKE;
      break;
    default:
      /* Oops, don't know what's wrong */
      ssl_errordump("Error in ssl_handshake");
      state = -1;
    }
  } else {
    state = ssl_accept(ssl);
  }
  return state;
}
Пример #3
0
/** Given an accepted connection on the listening socket, set up SSL.
 * \param sock an accepted socket (returned by accept())
 * \param state pointer to place to return connection state.
 * \return an SSL object to associate with the listen end of this connection.
 */
SSL *
ssl_listen(int sock, int *state)
{
  SSL *ssl;
  ssl = ssl_setup_socket(sock);
  *state = ssl_accept(ssl);
  return ssl;
}
Пример #4
0
int
vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess)
{
  if (p_sess->data_use_ssl)
  {
    if (!ssl_accept(p_sess, p_sess->data_fd))
    {
      vsf_cmdio_write(
        p_sess, FTP_DATATLSBAD, "Secure connection negotiation failed.");
      return 0;
    }
  }
  return 1;
}
Пример #5
0
int Sys_accept_SSL(int sockfd)
{
    if (sockfd != INVALID_SOCKET)
    {
        if (g_enableSSL)
        {
            int rc = ssl_accept(sockfd);
            if (rc == -1)
            {   // SSL problem
                close(sockfd);
                return -1;
            }
        }
    }

    return sockfd;
}
Пример #6
0
int Sys_accept(int listenfd, struct sockaddr* cliaddr, int* addrlen)
{
    int sockfd = accept(listenfd, cliaddr, (socklen_t*)addrlen);

    if (sockfd != INVALID_SOCKET)
    {
        if (g_enableSSL)
        {
            g_AcceptSock = sockfd;
            int rc = ssl_accept(sockfd);
            g_AcceptSock = 0;

            if (rc == -1)
            {   // SSL problem
                close(sockfd);
                return -1;
            }
        }
    }

    return sockfd;
}
Пример #7
0
int
vsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess)
{
  int ret = 0;
  if (!p_sess->data_use_ssl)
  {
    return 1;
  }
  if (!p_sess->ssl_slave_active)
  {
    ret = ssl_accept(p_sess, p_sess->data_fd);
  }
  else
  {
    int sock_ret;
    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE);
    priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd);
    sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd);
    if (sock_ret == PRIV_SOCK_RESULT_OK)
    {
      ret = 1;
    }
  }
  if (ret != 1)
  {
    static struct mystr s_err_msg;
    str_alloc_text(&s_err_msg, "SSL connection failed");
    if (tunable_require_ssl_reuse)
    {
      str_append_text(&s_err_msg, "; session reuse required");
      str_append_text(
          &s_err_msg, ": see require_ssl_reuse option in vsftpd.conf man page");
    }
    vsf_cmdio_write_str(p_sess, FTP_DATATLSBAD, &s_err_msg);
  }
  return ret;
}
Пример #8
0
/* Handle the connection of a client.
 */
static void connection_handler(t_session *session) {
	int result;
#ifdef ENABLE_SSL
	t_ssl_accept_data sad;
#endif

#ifdef ENABLE_DEBUG
	session->current_task = "thread started";
#endif

#ifdef ENABLE_SSL
	if (session->binding->use_ssl) {
		sad.context         = &(session->ssl_context);
		sad.client_fd       = &(session->client_socket);
		sad.private_key     = session->binding->private_key;
		sad.certificate     = session->binding->certificate;
		sad.ca_certificate  = session->binding->ca_certificate;
		sad.ca_crl          = session->binding->ca_crl;

		sad.timeout         = session->kept_alive == 0 ? session->binding->time_for_1st_request : session->binding->time_for_request;
		sad.min_ssl_version = session->config->min_ssl_version;
		sad.dh_size         = session->config->dh_size;
#ifdef ENABLE_DEBUG
		sad.thread_id       = session->thread_id;
		session->current_task = "ssl accept";
#endif
		switch (ssl_accept(&sad)) {
			case SSL_HANDSHAKE_NO_MATCH:
				log_system(session, "No cypher overlap during SSL handshake.");
				break;
			case SSL_HANDSHAKE_TIMEOUT:
				handle_timeout(session);
				break;
			case SSL_HANDSHAKE_OKE:
				session->socket_open = true;
				break;
		}
	} else
#endif
		session->socket_open = true;

	if (session->socket_open) {
#ifdef ENABLE_MONITOR
		if (session->config->monitor_enabled) {
			monitor_count_connection(session);
		}
#endif

		do {
			result = serve_client(session);
			handle_request_result(session, result);
#ifdef ENABLE_TOMAHAWK
			if (session->parsing_oke) {
				show_request_to_admins(session->method, session->request_uri, session->http_version, &(session->ip_address),
				                       session->http_headers, session->return_code, session->bytes_sent);
			}
#endif

#ifdef ENABLE_DEBUG
			session->current_task = "request done";
#endif

			if (session->socket_open) {
				/* Flush the output-buffer
				 */
				if (send_buffer(session, NULL, 0) == -1) {
					session->keep_alive = false;
				}
			}

#ifdef ENABLE_MONITOR
			if (session->config->monitor_enabled) {
				monitor_count_host(session);
			}
#endif
			reset_session(session);
#ifdef ENABLE_DEBUG
			session->current_task = "session reset";
#endif

			if ((session->kept_alive > 0) && (session->config->ban_on_flooding > 0)) {
				if (client_is_flooding(session)) {
					if (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny) {
						ban_ip(&(session->ip_address), session->config->ban_on_flooding, session->config->kick_on_ban);
						log_system(session, "Client banned because of flooding");
						session->keep_alive = false;
#ifdef ENABLE_MONITOR
						if (session->config->monitor_enabled) {
							monitor_count_ban(session);
						}
#endif
					}
				}
			}
		} while (session->keep_alive && session->socket_open);
#ifdef ENABLE_DEBUG
		session->current_task = "session done";
#endif

		destroy_session(session);
		close_socket(session);
	} else {
		close(session->client_socket);
	}

	if (session->config->reconnect_delay > 0) {
		mark_client_for_removal(session, session->config->reconnect_delay);
	} else {
		remove_client(session, true);
	}

#ifdef ENABLE_DEBUG
	/* Show memory usage by thread
	 */
	memdbg_print_log(false);
#endif

	/* Client session ends here
	 */
#ifndef ENABLE_THREAD_POOL
	pthread_exit(NULL);
#endif
}
Пример #9
0
/* Handle the connection of a client.
 */
static void connection_handler(t_session *session) {
	int result;
#ifdef ENABLE_SSL
	t_ssl_accept_data sad;
#endif
#ifdef ENABLE_MONITOR
	int connections;

#ifdef ENABLE_DEBUG
	session->current_task = "thread started";
#endif

	connections = ++open_connections;
	if (session->config->monitor_enabled) {
		if (connections > session->config->monitor_stats.simultaneous_connections) {
			session->config->monitor_stats.simultaneous_connections = connections;
		}
	}
#endif

#ifdef ENABLE_SSL
	if (session->binding->use_ssl) {
		sad.context         = &(session->ssl_context);
		sad.client_fd       = &(session->client_socket);
		sad.private_key     = session->binding->private_key;
		sad.certificate     = session->binding->certificate;
		sad.ca_certificate  = session->binding->ca_certificate;
		sad.ca_crl          = session->binding->ca_crl;

		sad.timeout         = session->kept_alive == 0 ? session->binding->time_for_1st_request : session->binding->time_for_request;
		sad.min_ssl_version = session->config->min_ssl_version;
		sad.dh_size         = session->config->dh_size;
#ifdef ENABLE_DEBUG
		session->current_task = "ssl accept";
#endif
		switch (ssl_accept(&sad)) {
			case -2:
				handle_timeout(session);
				break;
			case 0:
				session->socket_open = true;
				break;
		}
	} else
#endif
		session->socket_open = true;

	if (session->socket_open) {
		do {
			result = serve_client(session);
			handle_request_result(session, result);

#ifdef ENABLE_DEBUG
			session->current_task = "request done";
#endif

			if (session->socket_open) {
				send_buffer(session, NULL, 0); /* Flush the output-buffer */
			}

#ifdef ENABLE_MONITOR
			if (session->config->monitor_enabled) {
				monitor_counter_request(session);
				if (session->host->monitor_requests && (result > 0)) {
					monitor_request(session);
				}
			}
#endif
			reset_session(session);
#ifdef ENABLE_DEBUG
			session->current_task = "session reset";
#endif

			if ((session->kept_alive > 0) && (session->config->ban_on_flooding > 0)) {
				if (client_is_flooding(session)) {
					if (ip_allowed(&(session->ip_address), session->config->banlist_mask) != deny) {
						ban_ip(&(session->ip_address), session->config->ban_on_flooding, session->config->kick_on_ban);
						log_system(session, "Client banned because of flooding");
						session->keep_alive = false;
#ifdef ENABLE_MONITOR
						if (session->config->monitor_enabled) {
							monitor_counter_ban(session);
						}
#endif
					}
				}
			}
		} while (session->keep_alive && session->socket_open);
#ifdef ENABLE_DEBUG
		session->current_task = "session done";
#endif

		destroy_session(session);
		close_socket(session);
	} else {
		close(session->client_socket);
	}

#ifdef ENABLE_MONITOR
	open_connections--;
#endif

	if (session->config->reconnect_delay > 0) {
		mark_client_for_removal(session, session->config->reconnect_delay);
	} else {
		remove_client(session, true);
	}

	/* Client session ends here
	 */
#ifndef ENABLE_THREAD_POOL
	pthread_exit(NULL);
#endif
}
Пример #10
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");
    }
  }
}