From b8d3301d34f383f039071214872570385de1bb59 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 10 Sep 2015 01:02:44 +0200 Subject: [PATCH 1/9] SASL support The only supported methods are PLAIN and EXTERNAL, the latter is untested as of now. The code gets the values from the keys named sasl_{mechanism,username,password} specified for each chatnet. --- src/core/server-setup-rec.h | 3 + src/irc/core/Makefile.am | 2 + src/irc/core/irc-chatnets.c | 6 +- src/irc/core/irc-chatnets.h | 9 ++- src/irc/core/irc-core.c | 5 +- src/irc/core/irc-servers-setup.c | 24 ++++++ src/irc/core/irc-servers.c | 4 + src/irc/core/irc-servers.h | 4 + src/irc/core/sasl.c | 134 +++++++++++++++++++++++++++++++ src/irc/core/sasl.h | 14 ++++ 10 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 src/irc/core/sasl.c create mode 100644 src/irc/core/sasl.h diff --git a/src/core/server-setup-rec.h b/src/core/server-setup-rec.h index ecdde3f3..2c9614c7 100644 --- a/src/core/server-setup-rec.h +++ b/src/core/server-setup-rec.h @@ -8,6 +8,9 @@ char *address; int port; char *password; +int sasl_mechanism; +char *sasl_password; + char *ssl_cert; char *ssl_pkey; char *ssl_pass; diff --git a/src/irc/core/Makefile.am b/src/irc/core/Makefile.am index 7d885d20..20caaeb1 100644 --- a/src/irc/core/Makefile.am +++ b/src/irc/core/Makefile.am @@ -27,6 +27,7 @@ libirc_core_a_SOURCES = \ irc-servers-setup.c \ irc-session.c \ irc-cap.c \ + sasl.c \ lag.c \ massjoin.c \ modes.c \ @@ -50,6 +51,7 @@ pkginc_irc_core_HEADERS = \ irc-servers.h \ irc-servers-setup.h \ irc-cap.h \ + sasl.h \ modes.h \ mode-lists.h \ module.h \ diff --git a/src/irc/core/irc-chatnets.c b/src/irc/core/irc-chatnets.c index d757bf8d..cfb7deec 100644 --- a/src/irc/core/irc-chatnets.c +++ b/src/irc/core/irc-chatnets.c @@ -48,6 +48,10 @@ static void sig_chatnet_read(IRC_CHATNET_REC *rec, CONFIG_NODE *node) rec->max_msgs = config_node_get_int(node, "max_msgs", 0); rec->max_modes = config_node_get_int(node, "max_modes", 0); rec->max_whois = config_node_get_int(node, "max_whois", 0); + + rec->sasl_mechanism = config_node_get_str(node, "sasl_mechanism", NULL); + rec->sasl_username = config_node_get_str(node, "sasl_username", NULL); + rec->sasl_password = config_node_get_str(node, "sasl_password", NULL); } static void sig_chatnet_saved(IRC_CHATNET_REC *rec, CONFIG_NODE *node) @@ -78,7 +82,7 @@ static void sig_chatnet_saved(IRC_CHATNET_REC *rec, CONFIG_NODE *node) static void sig_chatnet_destroyed(IRC_CHATNET_REC *rec) { if (IS_IRC_CHATNET(rec)) - g_free(rec->usermode); + g_free(rec->usermode); } diff --git a/src/irc/core/irc-chatnets.h b/src/irc/core/irc-chatnets.h index 22da90c5..2bb10fa9 100644 --- a/src/irc/core/irc-chatnets.h +++ b/src/irc/core/irc-chatnets.h @@ -17,12 +17,15 @@ struct _IRC_CHATNET_REC { #include "chatnet-rec.h" - char *usermode; + char *usermode; + + char *sasl_mechanism; + char *sasl_username; + char *sasl_password; int max_cmds_at_once; int cmd_queue_speed; - int max_query_chans; /* when syncing, max. number of channels to - put in one MODE/WHO command */ + int max_query_chans; /* when syncing, max. number of channels to put in one MODE/WHO command */ /* max. number of kicks/msgs/mode/whois per command */ int max_kicks, max_msgs, max_modes, max_whois; diff --git a/src/irc/core/irc-core.c b/src/irc/core/irc-core.c index e3ceeeef..a9221e02 100644 --- a/src/irc/core/irc-core.c +++ b/src/irc/core/irc-core.c @@ -27,6 +27,7 @@ #include "irc-channels.h" #include "irc-queries.h" #include "irc-cap.h" +#include "sasl.h" #include "irc-servers-setup.h" #include "channels-setup.h" @@ -119,6 +120,7 @@ void irc_core_init(void) netsplit_init(); irc_expandos_init(); cap_init(); + sasl_init(); settings_check(); module_register("core", "irc"); @@ -128,6 +130,7 @@ void irc_core_deinit(void) { signal_emit("chat protocol deinit", 1, chat_protocol_find("IRC")); + sasl_deinit(); cap_deinit(); irc_expandos_deinit(); netsplit_deinit(); @@ -140,7 +143,7 @@ void irc_core_deinit(void) irc_irc_deinit(); irc_servers_deinit(); irc_chatnets_deinit(); - irc_session_deinit(); + irc_session_deinit(); chat_protocol_unregister("IRC"); } diff --git a/src/irc/core/irc-servers-setup.c b/src/irc/core/irc-servers-setup.c index 5659991b..9a9a8347 100644 --- a/src/irc/core/irc-servers-setup.c +++ b/src/irc/core/irc-servers-setup.c @@ -28,6 +28,7 @@ #include "irc-chatnets.h" #include "irc-servers-setup.h" #include "irc-servers.h" +#include "sasl.h" /* Fill information to connection from server setup record */ static void sig_server_setup_fill_reconn(IRC_SERVER_CONNECT_REC *conn, @@ -79,6 +80,29 @@ static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn, conn->cmd_queue_speed = ircnet->cmd_queue_speed; if (ircnet->max_query_chans > 0) conn->max_query_chans = ircnet->max_query_chans; + + /* Validate the SASL parameters filled by sig_chatnet_read() */ + conn->sasl_mechanism = SASL_MECHANISM_NONE; + + if (ircnet->sasl_mechanism != NULL) { + if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "plain")) { + /* The PLAIN method needs both the username and the password */ + if (ircnet->sasl_username != NULL && *ircnet->sasl_username && + ircnet->sasl_password != NULL && *ircnet->sasl_password) { + conn->sasl_mechanism = SASL_MECHANISM_PLAIN; + conn->sasl_username = ircnet->sasl_username; + conn->sasl_password = ircnet->sasl_password; + } else + g_warning("The fields sasl_username and sasl_password are either undefined or empty"); + } + else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "external")) { + conn->sasl_mechanism = SASL_MECHANISM_EXTERNAL; + conn->sasl_username = NULL; + conn->sasl_password = NULL; + } + else + g_warning("Unsupported SASL mechanism \"%s\" selected", ircnet->sasl_mechanism); + } } static void init_userinfo(void) diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index e9920d91..ad4d09cc 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -33,6 +33,7 @@ #include "irc-servers-setup.h" #include "irc-servers.h" #include "irc-cap.h" +#include "sasl.h" #include "channel-rejoin.h" #include "servers-idle.h" #include "servers-reconnect.h" @@ -215,6 +216,9 @@ static void server_init(IRC_SERVER_REC *server) g_free(cmd); } + if (conn->sasl_mechanism != SASL_MECHANISM_NONE) + cap_toggle(server, "sasl", TRUE); + irc_send_cmd_now(server, "CAP LS"); if (conn->password != NULL && *conn->password != '\0') { diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index f809fab5..41c4b9c2 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -27,6 +27,10 @@ struct _IRC_SERVER_CONNECT_REC { char *usermode; char *alternate_nick; + int sasl_mechanism; + char *sasl_username; + char *sasl_password; + int max_cmds_at_once; int cmd_queue_speed; int max_query_chans; diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c new file mode 100644 index 00000000..8bffc3d9 --- /dev/null +++ b/src/irc/core/sasl.c @@ -0,0 +1,134 @@ +#include "module.h" +#include "misc.h" +#include "settings.h" + +#include "irc-cap.h" +#include "irc-servers.h" +#include "sasl.h" + +#define SASL_TIMEOUT (20 * 1000) // ms + +static gboolean sasl_timeout (IRC_SERVER_REC *server) +{ + /* The authentication timed out, we can't do much beside terminating it */ + g_critical("The authentication timed out, try increasing the timeout and check your connection " + "to the network."); + irc_send_cmd_now(server, "AUTHENTICATE *"); + cap_finish_negotiation(server); + + return G_SOURCE_REMOVE; +} + +static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *from) +{ + IRC_SERVER_CONNECT_REC *conn; + + conn = server->connrec; + + switch (conn->sasl_mechanism) { + case SASL_MECHANISM_PLAIN: + irc_send_cmd_now(server, "AUTHENTICATE PLAIN"); + break; + + case SASL_MECHANISM_EXTERNAL: + irc_send_cmd_now(server, "AUTHENTICATE EXTERNAL"); + break; + } + server->sasl_timeout = g_timeout_add(SASL_TIMEOUT, (GSourceFunc) sasl_timeout, server); +} + +static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *from) +{ + /* Stop any pending timeout, if any */ + g_source_remove(server->sasl_timeout); + + g_critical("Authentication failed, make sure your credentials are correct and that the mechanism " + "you have selected is supported by this server."); + + /* Terminate the negotiation */ + cap_finish_negotiation(server); +} + +static void sasl_already (IRC_SERVER_REC *server, const char *data, const char *from) +{ + g_source_remove(server->sasl_timeout); + + /* We're already authenticated, do nothing */ + cap_finish_negotiation(server); +} + +static void sasl_success (IRC_SERVER_REC *server, const char *data, const char *from) +{ + g_source_remove(server->sasl_timeout); + + /* The authentication succeeded, time to finish the CAP negotiation */ + g_warning("SASL authentication succeeded"); + cap_finish_negotiation(server); +} + +static void sasl_step (IRC_SERVER_REC *server, const char *data, const char *from) +{ + IRC_SERVER_CONNECT_REC *conn; + GString *req; + char *enc_req; + + conn = server->connrec; + + /* Stop the timer */ + g_source_remove(server->sasl_timeout); + + switch (conn->sasl_mechanism) { + case SASL_MECHANISM_PLAIN: + /* At this point we assume that conn->{username, password} are non-NULL. + * The PLAIN mechanism expects a NULL-separated string composed by the authorization identity, the + * authentication identity and the password. + * The authorization identity field is optional and can be omitted, the server will derive the + * identity by looking at the credentials provided. + * The whole request is then encoded in base64. */ + + req = g_string_new(NULL); + + g_string_append_c(req, '\0'); + g_string_append(req, conn->sasl_username); + g_string_append_c(req, '\0'); + g_string_append(req, conn->sasl_password); + + enc_req = g_base64_encode((const guchar *)req->str, req->len); + + irc_send_cmdv(server, "AUTHENTICATE %s", enc_req); + + g_free(enc_req); + g_string_free(req, TRUE); + break; + + case SASL_MECHANISM_EXTERNAL: + /* Empty response */ + irc_send_cmdv(server, "+"); + break; + } + + /* We expect a response within a reasonable time */ + server->sasl_timeout = g_timeout_add(SASL_TIMEOUT, (GSourceFunc) sasl_timeout, server); +} + +void sasl_init(void) +{ + signal_add_first("server cap ack sasl", (SIGNAL_FUNC) sasl_start); + signal_add_first("event authenticate", (SIGNAL_FUNC) sasl_step); + signal_add_first("event 900", (SIGNAL_FUNC) sasl_success); + signal_add_first("event 902", (SIGNAL_FUNC) sasl_fail); + signal_add_first("event 904", (SIGNAL_FUNC) sasl_fail); + signal_add_first("event 905", (SIGNAL_FUNC) sasl_fail); + signal_add_first("event 907", (SIGNAL_FUNC) sasl_already); +} + +void sasl_deinit(void) +{ + signal_remove("server cap ack sasl", (SIGNAL_FUNC) sasl_start); + signal_remove("event authenticate", (SIGNAL_FUNC) sasl_step); + signal_remove("event 900", (SIGNAL_FUNC) sasl_success); + signal_remove("event 902", (SIGNAL_FUNC) sasl_fail); + signal_remove("event 904", (SIGNAL_FUNC) sasl_fail); + signal_remove("event 905", (SIGNAL_FUNC) sasl_fail); + signal_remove("event 907", (SIGNAL_FUNC) sasl_already); +} diff --git a/src/irc/core/sasl.h b/src/irc/core/sasl.h new file mode 100644 index 00000000..fcf87e16 --- /dev/null +++ b/src/irc/core/sasl.h @@ -0,0 +1,14 @@ +#ifndef __SASL_H +#define __SASL_H + +enum { + SASL_MECHANISM_NONE = 0, + SASL_MECHANISM_PLAIN, + SASL_MECHANISM_EXTERNAL, + SASL_MECHANISM_MAX +}; + +void sasl_init(void); +void sasl_deinit(void); + +#endif From c90c7deac37bea6754c9c2715230429fd49e8e81 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 00:58:01 +0200 Subject: [PATCH 2/9] Address all the points outlined in the first review Replace G_SOURCE_REMOVE with FALSE for the compatibility sake. Zero the timeout id after g_source_remove and when exipred. Save the sasl_* options in sig_chatnet_saved(). --- src/irc/core/irc-chatnets.c | 9 ++++++++- src/irc/core/sasl.c | 24 +++++++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/irc/core/irc-chatnets.c b/src/irc/core/irc-chatnets.c index cfb7deec..b9b221b8 100644 --- a/src/irc/core/irc-chatnets.c +++ b/src/irc/core/irc-chatnets.c @@ -60,7 +60,7 @@ static void sig_chatnet_saved(IRC_CHATNET_REC *rec, CONFIG_NODE *node) return; if (rec->usermode != NULL) - iconfig_node_set_str(node, "usermode", rec->usermode); + iconfig_node_set_str(node, "usermode", rec->usermode); if (rec->max_cmds_at_once > 0) iconfig_node_set_int(node, "cmdmax", rec->max_cmds_at_once); @@ -77,6 +77,13 @@ static void sig_chatnet_saved(IRC_CHATNET_REC *rec, CONFIG_NODE *node) iconfig_node_set_int(node, "max_modes", rec->max_modes); if (rec->max_whois > 0) iconfig_node_set_int(node, "max_whois", rec->max_whois); + + if (rec->sasl_mechanism != NULL) + iconfig_node_set_str(node, "sasl_mechanism", rec->sasl_mechanism); + if (rec->sasl_username != NULL) + iconfig_node_set_str(node, "sasl_username", rec->sasl_username); + if (rec->sasl_password != NULL) + iconfig_node_set_str(node, "sasl_password", rec->sasl_password); } static void sig_chatnet_destroyed(IRC_CHATNET_REC *rec) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 8bffc3d9..4b221176 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -16,7 +16,9 @@ static gboolean sasl_timeout (IRC_SERVER_REC *server) irc_send_cmd_now(server, "AUTHENTICATE *"); cap_finish_negotiation(server); - return G_SOURCE_REMOVE; + server->sasl_timeout = -1; + + return FALSE; } static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *from) @@ -40,7 +42,10 @@ static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *fr static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *from) { /* Stop any pending timeout, if any */ - g_source_remove(server->sasl_timeout); + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } g_critical("Authentication failed, make sure your credentials are correct and that the mechanism " "you have selected is supported by this server."); @@ -51,7 +56,10 @@ static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *fro static void sasl_already (IRC_SERVER_REC *server, const char *data, const char *from) { - g_source_remove(server->sasl_timeout); + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } /* We're already authenticated, do nothing */ cap_finish_negotiation(server); @@ -59,7 +67,10 @@ static void sasl_already (IRC_SERVER_REC *server, const char *data, const char * static void sasl_success (IRC_SERVER_REC *server, const char *data, const char *from) { - g_source_remove(server->sasl_timeout); + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } /* The authentication succeeded, time to finish the CAP negotiation */ g_warning("SASL authentication succeeded"); @@ -75,7 +86,10 @@ static void sasl_step (IRC_SERVER_REC *server, const char *data, const char *fro conn = server->connrec; /* Stop the timer */ - g_source_remove(server->sasl_timeout); + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } switch (conn->sasl_mechanism) { case SASL_MECHANISM_PLAIN: From 171b67441d64a85a23daf5018159f167eb7fe583 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 01:17:18 +0200 Subject: [PATCH 3/9] Replace spaces with tabs --- src/irc/core/sasl.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 4b221176..0e343299 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -16,7 +16,7 @@ static gboolean sasl_timeout (IRC_SERVER_REC *server) irc_send_cmd_now(server, "AUTHENTICATE *"); cap_finish_negotiation(server); - server->sasl_timeout = -1; + server->sasl_timeout = -1; return FALSE; } @@ -42,10 +42,10 @@ static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *fr static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *from) { /* Stop any pending timeout, if any */ - if (server->sasl_timeout != -1) { - g_source_remove(server->sasl_timeout); - server->sasl_timeout = -1; - } + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } g_critical("Authentication failed, make sure your credentials are correct and that the mechanism " "you have selected is supported by this server."); @@ -56,10 +56,10 @@ static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *fro static void sasl_already (IRC_SERVER_REC *server, const char *data, const char *from) { - if (server->sasl_timeout != -1) { - g_source_remove(server->sasl_timeout); - server->sasl_timeout = -1; - } + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } /* We're already authenticated, do nothing */ cap_finish_negotiation(server); @@ -67,10 +67,10 @@ static void sasl_already (IRC_SERVER_REC *server, const char *data, const char * static void sasl_success (IRC_SERVER_REC *server, const char *data, const char *from) { - if (server->sasl_timeout != -1) { - g_source_remove(server->sasl_timeout); - server->sasl_timeout = -1; - } + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } /* The authentication succeeded, time to finish the CAP negotiation */ g_warning("SASL authentication succeeded"); @@ -86,10 +86,10 @@ static void sasl_step (IRC_SERVER_REC *server, const char *data, const char *fro conn = server->connrec; /* Stop the timer */ - if (server->sasl_timeout != -1) { - g_source_remove(server->sasl_timeout); - server->sasl_timeout = -1; - } + if (server->sasl_timeout != -1) { + g_source_remove(server->sasl_timeout); + server->sasl_timeout = -1; + } switch (conn->sasl_mechanism) { case SASL_MECHANISM_PLAIN: From 6645d0d38dc4627a9553235a98df4f4717a1fc6f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 22:09:47 +0200 Subject: [PATCH 4/9] Explicitly set the authorization id during the PLAIN handshake On error show the user the message sent by the server. --- src/irc/core/sasl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 0e343299..4d52e3c0 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -47,8 +47,7 @@ static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *fro server->sasl_timeout = -1; } - g_critical("Authentication failed, make sure your credentials are correct and that the mechanism " - "you have selected is supported by this server."); + g_critical("Authentication failed with reason \"%s\"", data); /* Terminate the negotiation */ cap_finish_negotiation(server); @@ -93,15 +92,15 @@ static void sasl_step (IRC_SERVER_REC *server, const char *data, const char *fro switch (conn->sasl_mechanism) { case SASL_MECHANISM_PLAIN: - /* At this point we assume that conn->{username, password} are non-NULL. + /* At this point we assume that conn->sasl_{username, password} are non-NULL. * The PLAIN mechanism expects a NULL-separated string composed by the authorization identity, the * authentication identity and the password. - * The authorization identity field is optional and can be omitted, the server will derive the - * identity by looking at the credentials provided. + * The authorization identity field is explicitly set to the user provided username. * The whole request is then encoded in base64. */ req = g_string_new(NULL); + g_string_append(req, conn->sasl_username); g_string_append_c(req, '\0'); g_string_append(req, conn->sasl_username); g_string_append_c(req, '\0'); From 55387dd93df4cff349c5696ab1bcb87801f4443f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 22:23:38 +0200 Subject: [PATCH 5/9] Handle event 906 and 908 --- src/irc/core/sasl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 4d52e3c0..bf13dd21 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -132,7 +132,9 @@ void sasl_init(void) signal_add_first("event 902", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 904", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 905", (SIGNAL_FUNC) sasl_fail); + signal_add_first("event 906", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 907", (SIGNAL_FUNC) sasl_already); + signal_add_first("event 908", (SIGNAL_FUNC) sasl_fail); } void sasl_deinit(void) @@ -143,5 +145,7 @@ void sasl_deinit(void) signal_remove("event 902", (SIGNAL_FUNC) sasl_fail); signal_remove("event 904", (SIGNAL_FUNC) sasl_fail); signal_remove("event 905", (SIGNAL_FUNC) sasl_fail); + signal_remove("event 906", (SIGNAL_FUNC) sasl_fail); signal_remove("event 907", (SIGNAL_FUNC) sasl_already); + signal_remove("event 908", (SIGNAL_FUNC) sasl_fail); } From 1f114d75c6db16726bcb930044b7312e4c851eaa Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 23:17:46 +0200 Subject: [PATCH 6/9] Consider the SASL handshake successful on 903 --- src/irc/core/sasl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index bf13dd21..8f3b823f 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -128,7 +128,7 @@ void sasl_init(void) { signal_add_first("server cap ack sasl", (SIGNAL_FUNC) sasl_start); signal_add_first("event authenticate", (SIGNAL_FUNC) sasl_step); - signal_add_first("event 900", (SIGNAL_FUNC) sasl_success); + signal_add_first("event 903", (SIGNAL_FUNC) sasl_success); signal_add_first("event 902", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 904", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 905", (SIGNAL_FUNC) sasl_fail); @@ -141,7 +141,7 @@ void sasl_deinit(void) { signal_remove("server cap ack sasl", (SIGNAL_FUNC) sasl_start); signal_remove("event authenticate", (SIGNAL_FUNC) sasl_step); - signal_remove("event 900", (SIGNAL_FUNC) sasl_success); + signal_remove("event 903", (SIGNAL_FUNC) sasl_success); signal_remove("event 902", (SIGNAL_FUNC) sasl_fail); signal_remove("event 904", (SIGNAL_FUNC) sasl_fail); signal_remove("event 905", (SIGNAL_FUNC) sasl_fail); From 49c4ea5fd94c9eee17dc5a8e0691ba1da9bf33b7 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 23:20:07 +0200 Subject: [PATCH 7/9] Parse the error string received by the server So that in case of SASL failure the user sees a nice error message. --- src/irc/core/sasl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 8f3b823f..874b67f3 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -41,16 +41,22 @@ static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *fr static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *from) { + char *params, *error; + /* Stop any pending timeout, if any */ if (server->sasl_timeout != -1) { g_source_remove(server->sasl_timeout); server->sasl_timeout = -1; } - g_critical("Authentication failed with reason \"%s\"", data); + params = event_get_params(data, 2, NULL, &error); + + g_critical("Authentication failed with reason \"%s\"", error); /* Terminate the negotiation */ cap_finish_negotiation(server); + + g_free(params); } static void sasl_already (IRC_SERVER_REC *server, const char *data, const char *from) From 24d32c28ee2d5dbd001cbe29fa5d90077c6be107 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 11 Sep 2015 23:21:33 +0200 Subject: [PATCH 8/9] Don't handle 908 as a critical failure "if the mechanism is unknown, 908 is optional, 904 (or equivalent error condition) is required" --- src/irc/core/sasl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 874b67f3..56e80f48 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -140,7 +140,6 @@ void sasl_init(void) signal_add_first("event 905", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 906", (SIGNAL_FUNC) sasl_fail); signal_add_first("event 907", (SIGNAL_FUNC) sasl_already); - signal_add_first("event 908", (SIGNAL_FUNC) sasl_fail); } void sasl_deinit(void) @@ -153,5 +152,4 @@ void sasl_deinit(void) signal_remove("event 905", (SIGNAL_FUNC) sasl_fail); signal_remove("event 906", (SIGNAL_FUNC) sasl_fail); signal_remove("event 907", (SIGNAL_FUNC) sasl_already); - signal_remove("event 908", (SIGNAL_FUNC) sasl_fail); } From 203c00938acad1da4a91a2c21afdac4ede08572a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 20 Sep 2015 23:13:43 +0200 Subject: [PATCH 9/9] Use formats instead of g_warning Add some copyright headers here and there too. --- docs/signals.txt | 4 +++ src/fe-common/irc/Makefile.am | 1 + src/fe-common/irc/fe-common-irc.c | 5 ++++ src/fe-common/irc/fe-sasl.c | 48 ++++++++++++++++++++++++++++++ src/fe-common/irc/module-formats.c | 2 ++ src/fe-common/irc/module-formats.h | 2 ++ src/irc/core/irc-servers-setup.c | 2 +- src/irc/core/sasl.c | 43 +++++++++++++++++++------- src/irc/core/sasl.h | 20 +++++++++++++ 9 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 src/fe-common/irc/fe-sasl.c diff --git a/docs/signals.txt b/docs/signals.txt index 5c40ce77..8b71fd95 100644 --- a/docs/signals.txt +++ b/docs/signals.txt @@ -136,6 +136,10 @@ irc-cap.c "server cap nak ", SERVER_REC "server cap end", SERVER_REC +sasl.c + "server sasl failure", SERVER_REC, char *reason + "server sasl success", SERVER_REC + irc.c: "server event", SERVER_REC, char *data, char *sender_nick, char *sender_address diff --git a/src/fe-common/irc/Makefile.am b/src/fe-common/irc/Makefile.am index 463f145c..a5dd4c77 100644 --- a/src/fe-common/irc/Makefile.am +++ b/src/fe-common/irc/Makefile.am @@ -26,6 +26,7 @@ real_sources = \ fe-netsplit.c \ fe-common-irc.c \ fe-whois.c \ + fe-sasl.c \ irc-completion.c \ module-formats.c diff --git a/src/fe-common/irc/fe-common-irc.c b/src/fe-common/irc/fe-common-irc.c index d6ab30ce..4a3ef1d3 100644 --- a/src/fe-common/irc/fe-common-irc.c +++ b/src/fe-common/irc/fe-common-irc.c @@ -69,6 +69,9 @@ void fe_netjoin_deinit(void); void fe_whois_init(void); void fe_whois_deinit(void); +void fe_sasl_init(void); +void fe_sasl_deinit(void); + void irc_completion_init(void); void irc_completion_deinit(void); @@ -91,6 +94,7 @@ void fe_common_irc_init(void) fe_netsplit_init(); fe_netjoin_init(); fe_whois_init(); + fe_sasl_init(); irc_completion_init(); settings_check(); @@ -116,6 +120,7 @@ void fe_common_irc_deinit(void) fe_netsplit_deinit(); fe_netjoin_deinit(); fe_whois_deinit(); + fe_sasl_deinit(); irc_completion_deinit(); theme_unregister(); diff --git a/src/fe-common/irc/fe-sasl.c b/src/fe-common/irc/fe-sasl.c new file mode 100644 index 00000000..331b38b0 --- /dev/null +++ b/src/fe-common/irc/fe-sasl.c @@ -0,0 +1,48 @@ +/* + fe-sasl.c : irssi + + Copyright (C) 2015 The Lemon Man + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include "module-formats.h" +#include "signals.h" +#include "levels.h" + +#include "printtext.h" + +static void sig_sasl_success(IRC_SERVER_REC *server) +{ + printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_SASL_SUCCESS); +} + +static void sig_sasl_failure(IRC_SERVER_REC *server, const char *reason) +{ + printformat(server, NULL, MSGLEVEL_CRAP, IRCTXT_SASL_ERROR, reason); +} + +void fe_sasl_init(void) +{ + signal_add("server sasl success", (SIGNAL_FUNC) sig_sasl_success); + signal_add("server sasl failure", (SIGNAL_FUNC) sig_sasl_failure); +} + +void fe_sasl_deinit(void) +{ + signal_remove("server sasl success", (SIGNAL_FUNC) sig_sasl_success); + signal_remove("server sasl failure", (SIGNAL_FUNC) sig_sasl_failure); +} diff --git a/src/fe-common/irc/module-formats.c b/src/fe-common/irc/module-formats.c index 6eaf18e8..f7b074ec 100644 --- a/src/fe-common/irc/module-formats.c +++ b/src/fe-common/irc/module-formats.c @@ -44,6 +44,8 @@ FORMAT_REC fecommon_irc_formats[] = { { "setupserver_header", "%#Server Port Network Settings", 0 }, { "setupserver_line", "%#%|$[!20]0 $[5]1 $[10]2 $3", 4, { 0, 1, 0, 0 } }, { "setupserver_footer", "", 0 }, + { "sasl_success", "SASL authentication succeeded", 0 }, + { "sasl_error", "Cannot authenticate via SASL ($0)", 1, { 0 } }, /* ---- */ { NULL, "Channels", 0 }, diff --git a/src/fe-common/irc/module-formats.h b/src/fe-common/irc/module-formats.h index 34dd3efc..c45f4562 100644 --- a/src/fe-common/irc/module-formats.h +++ b/src/fe-common/irc/module-formats.h @@ -22,6 +22,8 @@ enum { IRCTXT_SETUPSERVER_HEADER, IRCTXT_SETUPSERVER_LINE, IRCTXT_SETUPSERVER_FOOTER, + IRCTXT_SASL_SUCCESS, + IRCTXT_SASL_ERROR, IRCTXT_FILL_2, diff --git a/src/irc/core/irc-servers-setup.c b/src/irc/core/irc-servers-setup.c index 9a9a8347..f5e4f8f4 100644 --- a/src/irc/core/irc-servers-setup.c +++ b/src/irc/core/irc-servers-setup.c @@ -93,7 +93,7 @@ static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn, conn->sasl_username = ircnet->sasl_username; conn->sasl_password = ircnet->sasl_password; } else - g_warning("The fields sasl_username and sasl_password are either undefined or empty"); + g_warning("The fields sasl_username and sasl_password are either missing or empty"); } else if (!g_ascii_strcasecmp(ircnet->sasl_mechanism, "external")) { conn->sasl_mechanism = SASL_MECHANISM_EXTERNAL; diff --git a/src/irc/core/sasl.c b/src/irc/core/sasl.c index 56e80f48..a04eaf45 100644 --- a/src/irc/core/sasl.c +++ b/src/irc/core/sasl.c @@ -1,3 +1,23 @@ +/* + fe-sasl.c : irssi + + Copyright (C) 2015 The Lemon Man + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + #include "module.h" #include "misc.h" #include "settings.h" @@ -8,20 +28,20 @@ #define SASL_TIMEOUT (20 * 1000) // ms -static gboolean sasl_timeout (IRC_SERVER_REC *server) +static gboolean sasl_timeout(IRC_SERVER_REC *server) { /* The authentication timed out, we can't do much beside terminating it */ - g_critical("The authentication timed out, try increasing the timeout and check your connection " - "to the network."); irc_send_cmd_now(server, "AUTHENTICATE *"); cap_finish_negotiation(server); server->sasl_timeout = -1; + signal_emit("server sasl failure", 2, server, "The authentication timed out"); + return FALSE; } -static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *from) +static void sasl_start(IRC_SERVER_REC *server, const char *data, const char *from) { IRC_SERVER_CONNECT_REC *conn; @@ -39,7 +59,7 @@ static void sasl_start (IRC_SERVER_REC *server, const char *data, const char *fr server->sasl_timeout = g_timeout_add(SASL_TIMEOUT, (GSourceFunc) sasl_timeout, server); } -static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *from) +static void sasl_fail(IRC_SERVER_REC *server, const char *data, const char *from) { char *params, *error; @@ -51,7 +71,7 @@ static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *fro params = event_get_params(data, 2, NULL, &error); - g_critical("Authentication failed with reason \"%s\"", error); + signal_emit("server sasl fail", 2, server, error); /* Terminate the negotiation */ cap_finish_negotiation(server); @@ -59,30 +79,33 @@ static void sasl_fail (IRC_SERVER_REC *server, const char *data, const char *fro g_free(params); } -static void sasl_already (IRC_SERVER_REC *server, const char *data, const char *from) +static void sasl_already(IRC_SERVER_REC *server, const char *data, const char *from) { if (server->sasl_timeout != -1) { g_source_remove(server->sasl_timeout); server->sasl_timeout = -1; } + signal_emit("server sasl success", 1, server); + /* We're already authenticated, do nothing */ cap_finish_negotiation(server); } -static void sasl_success (IRC_SERVER_REC *server, const char *data, const char *from) +static void sasl_success(IRC_SERVER_REC *server, const char *data, const char *from) { if (server->sasl_timeout != -1) { g_source_remove(server->sasl_timeout); server->sasl_timeout = -1; } + signal_emit("server sasl success", 1, server); + /* The authentication succeeded, time to finish the CAP negotiation */ - g_warning("SASL authentication succeeded"); cap_finish_negotiation(server); } -static void sasl_step (IRC_SERVER_REC *server, const char *data, const char *from) +static void sasl_step(IRC_SERVER_REC *server, const char *data, const char *from) { IRC_SERVER_CONNECT_REC *conn; GString *req; diff --git a/src/irc/core/sasl.h b/src/irc/core/sasl.h index fcf87e16..0693989d 100644 --- a/src/irc/core/sasl.h +++ b/src/irc/core/sasl.h @@ -1,3 +1,23 @@ +/* + fe-sasl.c : irssi + + Copyright (C) 2015 The Lemon Man + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + #ifndef __SASL_H #define __SASL_H