Move SSL_CTX *' into struct server_context'
				
					
				
			It didn't make much sense to parse the configuration values and load the SSL keys on each connection.
This commit is contained in:
		
							
								
								
									
										139
									
								
								src/kike.c
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								src/kike.c
									
									
									
									
									
								
							@@ -115,7 +115,6 @@ struct connection
 | 
				
			|||||||
	unsigned ssl_rx_want_tx : 1;        ///< SSL_read() wants to write
 | 
						unsigned ssl_rx_want_tx : 1;        ///< SSL_read() wants to write
 | 
				
			||||||
	unsigned ssl_tx_want_rx : 1;        ///< SSL_write() wants to read
 | 
						unsigned ssl_tx_want_rx : 1;        ///< SSL_write() wants to read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SSL_CTX *ssl_ctx;                   ///< SSL context
 | 
					 | 
				
			||||||
	SSL *ssl;                           ///< SSL connection
 | 
						SSL *ssl;                           ///< SSL connection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *nickname;                     ///< IRC nickname (main identifier)
 | 
						char *nickname;                     ///< IRC nickname (main identifier)
 | 
				
			||||||
@@ -143,8 +142,6 @@ connection_free (struct connection *self)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	if (!soft_assert (self->socket_fd == -1))
 | 
						if (!soft_assert (self->socket_fd == -1))
 | 
				
			||||||
		xclose (self->socket_fd);
 | 
							xclose (self->socket_fd);
 | 
				
			||||||
	if (self->ssl_ctx)
 | 
					 | 
				
			||||||
		SSL_CTX_free (self->ssl_ctx);
 | 
					 | 
				
			||||||
	if (self->ssl)
 | 
						if (self->ssl)
 | 
				
			||||||
		SSL_free (self->ssl);
 | 
							SSL_free (self->ssl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -211,11 +208,13 @@ struct server_context
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	int listen_fd;                      ///< Listening socket FD
 | 
						int listen_fd;                      ///< Listening socket FD
 | 
				
			||||||
	struct connection *clients;         ///< Client connections
 | 
						struct connection *clients;         ///< Client connections
 | 
				
			||||||
 | 
						SSL_CTX *ssl_ctx;                   ///< SSL context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct str_map users;               ///< Maps nicknames to connections
 | 
						struct str_map users;               ///< Maps nicknames to connections
 | 
				
			||||||
	struct str_map channels;            ///< Maps channel names to data
 | 
						struct str_map channels;            ///< Maps channel names to data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct poller poller;               ///< Manages polled description
 | 
						struct poller poller;               ///< Manages polled description
 | 
				
			||||||
 | 
						bool quitting;                      ///< User requested quitting
 | 
				
			||||||
	bool polling;                       ///< The event loop is running
 | 
						bool polling;                       ///< The event loop is running
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -234,6 +233,7 @@ server_context_init (struct server_context *self)
 | 
				
			|||||||
	str_map_init (&self->channels);
 | 
						str_map_init (&self->channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	poller_init (&self->poller);
 | 
						poller_init (&self->poller);
 | 
				
			||||||
 | 
						self->quitting = false;
 | 
				
			||||||
	self->polling = false;
 | 
						self->polling = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,6 +244,8 @@ server_context_free (struct server_context *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (self->listen_fd != -1)
 | 
						if (self->listen_fd != -1)
 | 
				
			||||||
		xclose (self->listen_fd);
 | 
							xclose (self->listen_fd);
 | 
				
			||||||
 | 
						if (self->ssl_ctx)
 | 
				
			||||||
 | 
							SSL_CTX_free (self->ssl_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: terminate the connections properly before this is called
 | 
						// TODO: terminate the connections properly before this is called
 | 
				
			||||||
	struct connection *link, *tmp;
 | 
						struct connection *link, *tmp;
 | 
				
			||||||
@@ -321,62 +323,29 @@ irc_ssl_verify_callback (int verify_ok, X509_STORE_CTX *ctx)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
irc_initialize_ssl (struct connection *conn)
 | 
					connection_initialize_ssl (struct connection *conn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct server_context *ctx = conn->ctx;
 | 
						// SSL support not enabled
 | 
				
			||||||
 | 
						if (!conn->ctx->ssl_ctx)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	conn->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
 | 
						conn->ssl = SSL_new (conn->ctx->ssl_ctx);
 | 
				
			||||||
	if (!conn->ssl_ctx)
 | 
					 | 
				
			||||||
		goto error_ssl_1;
 | 
					 | 
				
			||||||
	SSL_CTX_set_verify (conn->ssl_ctx,
 | 
					 | 
				
			||||||
		SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, irc_ssl_verify_callback);
 | 
					 | 
				
			||||||
	// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	conn->ssl = SSL_new (conn->ssl_ctx);
 | 
					 | 
				
			||||||
	if (!conn->ssl)
 | 
						if (!conn->ssl)
 | 
				
			||||||
		goto error_ssl_2;
 | 
							goto error_ssl_1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
 | 
					 | 
				
			||||||
	if (ssl_cert
 | 
					 | 
				
			||||||
	 && !SSL_CTX_use_certificate_chain_file (conn->ssl_ctx, ssl_cert))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// XXX: perhaps we should read the file ourselves for better messages
 | 
					 | 
				
			||||||
		print_error ("%s: %s", "setting the SSL client certificate failed",
 | 
					 | 
				
			||||||
			ERR_error_string (ERR_get_error (), NULL));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const char *ssl_key = str_map_find (&ctx->config, "ssl_key");
 | 
					 | 
				
			||||||
	if (ssl_key
 | 
					 | 
				
			||||||
	 && !SSL_use_PrivateKey_file (conn->ssl, ssl_key, SSL_FILETYPE_PEM))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// XXX: perhaps we should read the file ourselves for better messages
 | 
					 | 
				
			||||||
		print_error ("%s: %s", "setting the SSL private key failed",
 | 
					 | 
				
			||||||
			ERR_error_string (ERR_get_error (), NULL));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO: SSL_check_private_key(conn->ssl)?  It is has probably already been
 | 
					 | 
				
			||||||
	//   checked by SSL_use_PrivateKey_file() above.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SSL_set_accept_state (conn->ssl);
 | 
					 | 
				
			||||||
	if (!SSL_set_fd (conn->ssl, conn->socket_fd))
 | 
						if (!SSL_set_fd (conn->ssl, conn->socket_fd))
 | 
				
			||||||
		goto error_ssl_3;
 | 
							goto error_ssl_2;
 | 
				
			||||||
	// Gah, spare me your awkward semantics, I just want to push data!
 | 
						SSL_set_accept_state (conn->ssl);
 | 
				
			||||||
	// XXX: do we want SSL_MODE_AUTO_RETRY as well?  I guess not.
 | 
					 | 
				
			||||||
	SSL_set_mode (conn->ssl,
 | 
					 | 
				
			||||||
		SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
 | 
					 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error_ssl_3:
 | 
					error_ssl_2:
 | 
				
			||||||
	SSL_free (conn->ssl);
 | 
						SSL_free (conn->ssl);
 | 
				
			||||||
	conn->ssl = NULL;
 | 
						conn->ssl = NULL;
 | 
				
			||||||
error_ssl_2:
 | 
					 | 
				
			||||||
	SSL_CTX_free (conn->ssl_ctx);
 | 
					 | 
				
			||||||
	conn->ssl_ctx = NULL;
 | 
					 | 
				
			||||||
error_ssl_1:
 | 
					error_ssl_1:
 | 
				
			||||||
	// XXX: these error strings are really nasty; also there could be
 | 
						// XXX: these error strings are really nasty; also there could be
 | 
				
			||||||
	//   multiple errors on the OpenSSL stack.
 | 
						//   multiple errors on the OpenSSL stack.
 | 
				
			||||||
	print_error ("%s: %s", "could not initialize SSL",
 | 
						print_debug ("%s: %s: %s", "could not initialize SSL",
 | 
				
			||||||
		ERR_error_string (ERR_get_error (), NULL));
 | 
							conn->hostname, ERR_error_string (ERR_get_error (), NULL));
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -502,13 +471,11 @@ irc_try_write_ssl (struct connection *conn)
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
on_irc_client_ready (const struct pollfd *pfd, void *user_data)
 | 
					on_irc_client_ready (const struct pollfd *pfd, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// XXX: check/load `ssl_cert' and `ssl_key' earlier?
 | 
					 | 
				
			||||||
	struct connection *conn = user_data;
 | 
						struct connection *conn = user_data;
 | 
				
			||||||
	if (!conn->initialized)
 | 
						if (!conn->initialized)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		hard_assert (pfd->events == POLLIN);
 | 
							hard_assert (pfd->events == POLLIN);
 | 
				
			||||||
		// XXX: what with the error from irc_initialize_ssl()?
 | 
							if (irc_autodetect_ssl (conn) && !connection_initialize_ssl (conn))
 | 
				
			||||||
		if (irc_autodetect_ssl (conn) && !irc_initialize_ssl (conn))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			connection_abort (conn, NULL);
 | 
								connection_abort (conn, NULL);
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
@@ -599,6 +566,69 @@ on_irc_connection_available (const struct pollfd *pfd, void *user_data)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					irc_initialize_ssl (struct server_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
 | 
				
			||||||
 | 
						const char *ssl_key = str_map_find (&ctx->config, "ssl_key");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Only try to enable SSL support if the user configures it; it is not
 | 
				
			||||||
 | 
						// a failure if no one has requested it.
 | 
				
			||||||
 | 
						if (!ssl_cert && !ssl_key)
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ssl_cert)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_error ("no SSL certificate set");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!ssl_key)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_error ("no SSL private key set");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctx->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
 | 
				
			||||||
 | 
						if (!ctx->ssl_ctx)
 | 
				
			||||||
 | 
							goto error_ssl_1;
 | 
				
			||||||
 | 
						SSL_CTX_set_verify (ctx->ssl_ctx,
 | 
				
			||||||
 | 
							SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, irc_ssl_verify_callback);
 | 
				
			||||||
 | 
						// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// XXX: perhaps we should read the files ourselves for better messages
 | 
				
			||||||
 | 
						if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, ssl_cert))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_error ("%s: %s", "setting the SSL client certificate failed",
 | 
				
			||||||
 | 
								ERR_error_string (ERR_get_error (), NULL));
 | 
				
			||||||
 | 
							goto error_ssl_2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, ssl_key, SSL_FILETYPE_PEM))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							print_error ("%s: %s", "setting the SSL private key failed",
 | 
				
			||||||
 | 
								ERR_error_string (ERR_get_error (), NULL));
 | 
				
			||||||
 | 
							goto error_ssl_2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: SSL_CTX_check_private_key()?  It has probably already been checked
 | 
				
			||||||
 | 
						//   by SSL_CTX_use_PrivateKey_file() above.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Gah, spare me your awkward semantics, I just want to push data!
 | 
				
			||||||
 | 
						// XXX: do we want SSL_MODE_AUTO_RETRY as well?  I guess not.
 | 
				
			||||||
 | 
						SSL_CTX_set_mode (ctx->ssl_ctx,
 | 
				
			||||||
 | 
							SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_ssl_2:
 | 
				
			||||||
 | 
						SSL_CTX_free (ctx->ssl_ctx);
 | 
				
			||||||
 | 
						ctx->ssl_ctx = NULL;
 | 
				
			||||||
 | 
					error_ssl_1:
 | 
				
			||||||
 | 
						// XXX: these error strings are really nasty; also there could be
 | 
				
			||||||
 | 
						//   multiple errors on the OpenSSL stack.
 | 
				
			||||||
 | 
						print_error ("%s: %s", "could not initialize SSL",
 | 
				
			||||||
 | 
							ERR_error_string (ERR_get_error (), NULL));
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
irc_listen (struct server_context *ctx, struct error **e)
 | 
					irc_listen (struct server_context *ctx, struct error **e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -679,13 +709,14 @@ on_signal_pipe_readable (const struct pollfd *fd, struct server_context *ctx)
 | 
				
			|||||||
	char *dummy;
 | 
						char *dummy;
 | 
				
			||||||
	(void) read (fd->fd, &dummy, 1);
 | 
						(void) read (fd->fd, &dummy, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
						// TODO: send ERROR messages to anyone, wait for the messages to get
 | 
				
			||||||
	// TODO
 | 
						//   dispatched for a few seconds, RST the rest and quit.
 | 
				
			||||||
	if (g_termination_requested && !ctx->quitting)
 | 
						if (g_termination_requested && !ctx->quitting)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
		initiate_quit (ctx);
 | 
							initiate_quit (ctx);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@@ -778,6 +809,8 @@ main (int argc, char *argv[])
 | 
				
			|||||||
	poller_set (&ctx.poller, g_signal_pipe[0], POLLIN,
 | 
						poller_set (&ctx.poller, g_signal_pipe[0], POLLIN,
 | 
				
			||||||
		(poller_dispatcher_func) on_signal_pipe_readable, &ctx);
 | 
							(poller_dispatcher_func) on_signal_pipe_readable, &ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!irc_initialize_ssl (&ctx))
 | 
				
			||||||
 | 
							exit (EXIT_FAILURE);
 | 
				
			||||||
	if (!irc_listen (&ctx, &e))
 | 
						if (!irc_listen (&ctx, &e))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		print_error ("%s", e->message);
 | 
							print_error ("%s", e->message);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user