ZyklonB: better SSL configuration
Allow specifying a custom certificate bundle (can be handy for connecting to servers with a self-signed certificate). Enabled certificate verification by default. Renamed the "ssl_use" to just "ssl".
This commit is contained in:
parent
7951dc4d85
commit
efcb9d17e5
115
zyklonb.c
115
zyklonb.c
|
@ -33,8 +33,11 @@ static struct config_item g_config_table[] =
|
||||||
|
|
||||||
{ "irc_host", NULL, "Address of the IRC server" },
|
{ "irc_host", NULL, "Address of the IRC server" },
|
||||||
{ "irc_port", "6667", "Port of the IRC server" },
|
{ "irc_port", "6667", "Port of the IRC server" },
|
||||||
{ "ssl_use", "off", "Whether to use SSL" },
|
{ "ssl", "off", "Whether to use SSL" },
|
||||||
{ "ssl_cert", NULL, "Client SSL certificate (PEM)" },
|
{ "ssl_cert", NULL, "Client SSL certificate (PEM)" },
|
||||||
|
{ "ssl_verify", "on", "Whether to verify certificates" },
|
||||||
|
{ "ssl_ca_file", NULL, "OpenSSL CA bundle file" },
|
||||||
|
{ "ssl_ca_path", NULL, "OpenSSL CA bundle path" },
|
||||||
{ "autojoin", NULL, "Channels to join on start" },
|
{ "autojoin", NULL, "Channels to join on start" },
|
||||||
{ "reconnect", "on", "Whether to reconnect on error" },
|
{ "reconnect", "on", "Whether to reconnect on error" },
|
||||||
{ "reconnect_delay", "5", "Time between reconnecting" },
|
{ "reconnect_delay", "5", "Time between reconnecting" },
|
||||||
|
@ -294,16 +297,67 @@ irc_send (struct bot_context *ctx, const char *format, ...)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static bool
|
||||||
irc_ssl_verify_callback (int preverify_ok, X509_STORE_CTX *x509_ctx)
|
irc_get_boolean_from_config
|
||||||
|
(struct bot_context *ctx, const char *name, bool *value, struct error **e)
|
||||||
{
|
{
|
||||||
(void) x509_ctx;
|
const char *str = str_map_find (&ctx->config, name);
|
||||||
|
hard_assert (str != NULL);
|
||||||
|
|
||||||
if (!preverify_ok)
|
if (set_boolean_if_valid (value, str))
|
||||||
print_warning ("TLS certificate verification failed");
|
return true;
|
||||||
|
|
||||||
// We don't care; some encryption is always better than no encryption
|
error_set (e, "invalid configuration value for `%s'", name);
|
||||||
return 1;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
irc_initialize_ssl_ctx (struct bot_context *ctx, struct error **e)
|
||||||
|
{
|
||||||
|
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
|
||||||
|
|
||||||
|
bool verify;
|
||||||
|
if (!irc_get_boolean_from_config (ctx, "ssl_verify", &verify, e))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!verify)
|
||||||
|
SSL_CTX_set_verify (ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||||
|
|
||||||
|
const char *ca_file = str_map_find (&ctx->config, "ca_file");
|
||||||
|
const char *ca_path = str_map_find (&ctx->config, "ca_path");
|
||||||
|
|
||||||
|
struct error *error = NULL;
|
||||||
|
if (ca_file || ca_path)
|
||||||
|
{
|
||||||
|
if (SSL_CTX_load_verify_locations (ctx->ssl_ctx, ca_file, ca_path))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error_set (&error, "%s: %s",
|
||||||
|
"failed to set locations for the CA certificate bundle",
|
||||||
|
ERR_reason_error_string (ERR_get_error ()));
|
||||||
|
goto ca_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SSL_CTX_set_default_verify_paths (ctx->ssl_ctx))
|
||||||
|
{
|
||||||
|
error_set (&error, "%s: %s",
|
||||||
|
"couldn't load the default CA certificate bundle",
|
||||||
|
ERR_reason_error_string (ERR_get_error ()));
|
||||||
|
goto ca_error;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ca_error:
|
||||||
|
if (verify)
|
||||||
|
{
|
||||||
|
error_propagate (e, error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only inform the user if we're not actually verifying
|
||||||
|
print_warning ("%s", error->message);
|
||||||
|
error_free (error);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -313,10 +367,8 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
|
||||||
ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
|
ctx->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
|
||||||
if (!ctx->ssl_ctx)
|
if (!ctx->ssl_ctx)
|
||||||
goto error_ssl_1;
|
goto error_ssl_1;
|
||||||
if (!SSL_CTX_set_default_verify_paths (ctx->ssl_ctx))
|
if (!irc_initialize_ssl_ctx (ctx, e))
|
||||||
print_warning ("couldn't load TLS CA certificates");
|
goto error_ssl_2;
|
||||||
SSL_CTX_set_verify (ctx->ssl_ctx, SSL_VERIFY_PEER, irc_ssl_verify_callback);
|
|
||||||
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
|
|
||||||
|
|
||||||
ctx->ssl = SSL_new (ctx->ssl_ctx);
|
ctx->ssl = SSL_new (ctx->ssl_ctx);
|
||||||
if (!ctx->ssl)
|
if (!ctx->ssl)
|
||||||
|
@ -630,20 +682,14 @@ prepare_recovery_environment (void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
setup_recovery_handler (struct bot_context *ctx)
|
setup_recovery_handler (struct bot_context *ctx, struct error **e)
|
||||||
{
|
{
|
||||||
const char *recover_str = str_map_find (&ctx->config, "recover");
|
|
||||||
hard_assert (recover_str != NULL); // We have a default value for this
|
|
||||||
|
|
||||||
bool recover;
|
bool recover;
|
||||||
if (!set_boolean_if_valid (&recover, recover_str))
|
if (!irc_get_boolean_from_config (ctx, "recover", &recover, e))
|
||||||
{
|
return false;
|
||||||
print_error ("invalid configuration value for `%s'", "recover");
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (!recover)
|
if (!recover)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
// Make sure these signals aren't blocked, otherwise we would be unable
|
// Make sure these signals aren't blocked, otherwise we would be unable
|
||||||
// to handle them, making the critical conditions fatal.
|
// to handle them, making the critical conditions fatal.
|
||||||
|
@ -668,6 +714,7 @@ setup_recovery_handler (struct bot_context *ctx)
|
||||||
|| sigaction (SIGFPE, &sa, NULL) == -1
|
|| sigaction (SIGFPE, &sa, NULL) == -1
|
||||||
|| sigaction (SIGILL, &sa, NULL) == -1)
|
|| sigaction (SIGILL, &sa, NULL) == -1)
|
||||||
print_error ("sigaction: %s", strerror (errno));
|
print_error ("sigaction: %s", strerror (errno));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SOCKS 5/4a (blocking implementation) ------------------------------------
|
// --- SOCKS 5/4a (blocking implementation) ------------------------------------
|
||||||
|
@ -2000,7 +2047,6 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
||||||
{
|
{
|
||||||
const char *irc_host = str_map_find (&ctx->config, "irc_host");
|
const char *irc_host = str_map_find (&ctx->config, "irc_host");
|
||||||
const char *irc_port = str_map_find (&ctx->config, "irc_port");
|
const char *irc_port = str_map_find (&ctx->config, "irc_port");
|
||||||
const char *ssl_use_str = str_map_find (&ctx->config, "ssl_use");
|
|
||||||
|
|
||||||
const char *socks_host = str_map_find (&ctx->config, "socks_host");
|
const char *socks_host = str_map_find (&ctx->config, "socks_host");
|
||||||
const char *socks_port = str_map_find (&ctx->config, "socks_port");
|
const char *socks_port = str_map_find (&ctx->config, "socks_port");
|
||||||
|
@ -2012,7 +2058,7 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
||||||
const char *realname = str_map_find (&ctx->config, "realname");
|
const char *realname = str_map_find (&ctx->config, "realname");
|
||||||
|
|
||||||
// We have a default value for these
|
// We have a default value for these
|
||||||
hard_assert (irc_port && ssl_use_str && socks_port);
|
hard_assert (irc_port && socks_port);
|
||||||
hard_assert (nickname && username && realname);
|
hard_assert (nickname && username && realname);
|
||||||
|
|
||||||
// TODO: again, get rid of `struct error' in here. The question is: how
|
// TODO: again, get rid of `struct error' in here. The question is: how
|
||||||
|
@ -2024,11 +2070,8 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_ssl;
|
bool use_ssl;
|
||||||
if (!set_boolean_if_valid (&use_ssl, ssl_use_str))
|
if (!irc_get_boolean_from_config (ctx, "ssl", &use_ssl, e))
|
||||||
{
|
|
||||||
error_set (e, "invalid configuration value for `%s'", "use_ssl");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (socks_host)
|
if (socks_host)
|
||||||
{
|
{
|
||||||
|
@ -2078,13 +2121,8 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
||||||
static bool
|
static bool
|
||||||
parse_config (struct bot_context *ctx, struct error **e)
|
parse_config (struct bot_context *ctx, struct error **e)
|
||||||
{
|
{
|
||||||
const char *reconnect_str = str_map_find (&ctx->config, "reconnect");
|
if (!irc_get_boolean_from_config (ctx, "reconnect", &ctx->reconnect, e))
|
||||||
hard_assert (reconnect_str != NULL); // We have a default value for this
|
|
||||||
if (!set_boolean_if_valid (&ctx->reconnect, reconnect_str))
|
|
||||||
{
|
|
||||||
error_set (e, "invalid configuration value for `%s'", "reconnect");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
const char *delay_str = str_map_find (&ctx->config, "reconnect_delay");
|
const char *delay_str = str_map_find (&ctx->config, "reconnect_delay");
|
||||||
hard_assert (delay_str != NULL); // We have a default value for this
|
hard_assert (delay_str != NULL); // We have a default value for this
|
||||||
|
@ -2248,15 +2286,14 @@ main (int argc, char *argv[])
|
||||||
bot_context_init (&ctx);
|
bot_context_init (&ctx);
|
||||||
|
|
||||||
struct error *e = NULL;
|
struct error *e = NULL;
|
||||||
if (!read_config_file (&ctx.config, &e))
|
if (!read_config_file (&ctx.config, &e)
|
||||||
|
|| !setup_recovery_handler (&ctx, &e))
|
||||||
{
|
{
|
||||||
print_error ("error loading configuration: %s", e->message);
|
print_error ("%s", e->message);
|
||||||
error_free (e);
|
error_free (e);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_recovery_handler (&ctx);
|
|
||||||
|
|
||||||
poller_fd_init (&ctx.signal_event, &ctx.poller, g_signal_pipe[0]);
|
poller_fd_init (&ctx.signal_event, &ctx.poller, g_signal_pipe[0]);
|
||||||
ctx.signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable;
|
ctx.signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable;
|
||||||
ctx.signal_event.user_data = &ctx;
|
ctx.signal_event.user_data = &ctx;
|
||||||
|
|
Loading…
Reference in New Issue