diff --git a/NEWS b/NEWS index 8c56d81..1c1a528 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ * degesch: added a /squery command for IRCnet + * degesch: added trivial support for SASL EXTERNAL, enabled by adding "sasl" + to the respective server's "capabilities" list + * degesch: now supporting IRCv3.2 capability negotiation, including CAP DEL diff --git a/degesch.c b/degesch.c index eaf71fa..b186125 100644 --- a/degesch.c +++ b/degesch.c @@ -1721,6 +1721,7 @@ struct server struct strv cap_ls_buf; ///< Buffer for IRCv3.2 CAP LS bool cap_echo_message; ///< Whether the server echoes messages bool cap_away_notify; ///< Whether we get AWAY notifications + bool cap_sasl; ///< Whether SASL is available // Server-specific information (from RPL_ISUPPORT): @@ -4962,6 +4963,7 @@ irc_destroy_state (struct server *s) strv_reset (&s->cap_ls_buf); s->cap_away_notify = false; s->cap_echo_message = false; + s->cap_sasl = false; // Need to call this before server_init_specifics() irc_set_casemapping (s, irc_tolower, irc_strxfrm); @@ -6526,6 +6528,20 @@ irc_process_sent_message (const struct irc_message *msg, struct server *s) // --- Input handling ---------------------------------------------------------- +static void +irc_handle_authenticate (struct server *s, const struct irc_message *msg) +{ + if (msg->params.len < 1) + return; + + // Empty challenge -> empty response for e.g. SASL EXTERNAL, + // abort anything else as it doesn't make much sense to let the user do it + if (!strcmp (msg->params.vector[0], "+")) + irc_send (s, "AUTHENTICATE +"); + else + irc_send (s, "AUTHENTICATE *"); +} + static void irc_handle_away (struct server *s, const struct irc_message *msg) { @@ -6579,10 +6595,9 @@ irc_process_cap_ls (struct server *s) static void irc_toggle_cap (struct server *s, const char *cap, bool active) { - if (!strcasecmp_ascii (cap, "echo-message")) - s->cap_echo_message = active; - if (!strcasecmp_ascii (cap, "away-notify")) - s->cap_away_notify = active; + if (!strcasecmp_ascii (cap, "echo-message")) s->cap_echo_message = active; + if (!strcasecmp_ascii (cap, "away-notify")) s->cap_away_notify = active; + if (!strcasecmp_ascii (cap, "sasl")) s->cap_sasl = active; } static void @@ -6612,13 +6627,17 @@ irc_handle_cap (struct server *s, const struct irc_message *msg) } irc_toggle_cap (s, cap, active); } - irc_send (s, "CAP END"); + if (s->cap_sasl && s->transport == &g_transport_tls) + irc_send (s, "AUTHENTICATE EXTERNAL"); + else if (s->state == IRC_CONNECTED) + irc_send (s, "CAP END"); } else if (!strcasecmp_ascii (subcommand, "NAK")) { log_server_error (s, s->buffer, "#s: #S", "Capabilities not acknowledged", args); - irc_send (s, "CAP END"); + if (s->state == IRC_CONNECTED) + irc_send (s, "CAP END"); } else if (!strcasecmp_ascii (subcommand, "DEL")) { @@ -7280,22 +7299,23 @@ irc_handle_topic (struct server *s, const struct irc_message *msg) static struct irc_handler g_irc_handlers[] = { // This list needs to stay sorted - { "AWAY", irc_handle_away }, - { "CAP", irc_handle_cap }, - { "ERROR", irc_handle_error }, - { "INVITE", irc_handle_invite }, - { "JOIN", irc_handle_join }, - { "KICK", irc_handle_kick }, - { "KILL", irc_handle_kill }, - { "MODE", irc_handle_mode }, - { "NICK", irc_handle_nick }, - { "NOTICE", irc_handle_notice }, - { "PART", irc_handle_part }, - { "PING", irc_handle_ping }, - { "PRIVMSG", irc_handle_privmsg }, - { "QUIT", irc_handle_quit }, - { "TAGMSG", irc_handle_tagmsg }, - { "TOPIC", irc_handle_topic }, + { "AUTHENTICATE", irc_handle_authenticate }, + { "AWAY", irc_handle_away }, + { "CAP", irc_handle_cap }, + { "ERROR", irc_handle_error }, + { "INVITE", irc_handle_invite }, + { "JOIN", irc_handle_join }, + { "KICK", irc_handle_kick }, + { "KILL", irc_handle_kill }, + { "MODE", irc_handle_mode }, + { "NICK", irc_handle_nick }, + { "NOTICE", irc_handle_notice }, + { "PART", irc_handle_part }, + { "PING", irc_handle_ping }, + { "PRIVMSG", irc_handle_privmsg }, + { "QUIT", irc_handle_quit }, + { "TAGMSG", irc_handle_tagmsg }, + { "TOPIC", irc_handle_topic }, }; static bool @@ -7976,6 +7996,16 @@ irc_process_numeric (struct server *s, if (irc_handle_rpl_endofwho (s, msg)) buffer = NULL; break; + case IRC_ERR_NICKLOCKED: + case IRC_RPL_SASLSUCCESS: + case IRC_ERR_SASLFAIL: + case IRC_ERR_SASLTOOLONG: + case IRC_ERR_SASLABORTED: + case IRC_ERR_SASLALREADY: + if (s->state == IRC_CONNECTED) + irc_send (s, "CAP END"); + break; + case IRC_RPL_LIST: case IRC_ERR_UNKNOWNCOMMAND: diff --git a/kike-replies b/kike-replies index 942eb38..fc8d6df 100644 --- a/kike-replies +++ b/kike-replies @@ -85,3 +85,9 @@ 482 IRC_ERR_CHANOPRIVSNEEDED "%s :You're not channel operator" 501 IRC_ERR_UMODEUNKNOWNFLAG ":Unknown MODE flag" 502 IRC_ERR_USERSDONTMATCH ":Cannot change mode for other users" +902 IRC_ERR_NICKLOCKED ":You must use a nick assigned to you" +903 IRC_RPL_SASLSUCCESS ":SASL authentication successful" +904 IRC_ERR_SASLFAIL ":SASL authentication failed" +905 IRC_ERR_SASLTOOLONG ":SASL message too long" +906 IRC_ERR_SASLABORTED ":SASL authentication aborted" +907 IRC_ERR_SASLALREADY ":You have already authenticated using SASL"