diff --git a/src/common/hexchat.h b/src/common/hexchat.h index e5d8a654..063a55b7 100644 --- a/src/common/hexchat.h +++ b/src/common/hexchat.h @@ -586,6 +586,7 @@ typedef struct server unsigned int skip_next_whois:1; /* hide whois output */ unsigned int inside_whois:1; unsigned int doing_dns:1; /* /dns has been done */ + unsigned int retry_sasl:1; /* retrying another sasl mech */ unsigned int end_of_motd:1; /* end of motd reached (logged in) */ unsigned int sent_quit:1; /* sent a QUIT already? */ unsigned int use_listargs:1; /* undernet and dalnet need /list >0,<10000 */ diff --git a/src/common/inbound.c b/src/common/inbound.c index 912fbbd5..4e93b3cd 100644 --- a/src/common/inbound.c +++ b/src/common/inbound.c @@ -1771,6 +1771,29 @@ inbound_sasl_authenticate (server *serv, char *data) ircnet *net = (ircnet*)serv->network; char *user, *pass = NULL; const char *mech = sasl_mechanisms[serv->sasl_mech]; + int i; + + /* Got a list of supported mechanisms */ + if (strchr (data, ',') != NULL) + { + if (serv->sasl_mech == MECH_EXTERNAL) + goto sasl_abort; + + /* Use most secure one supported */ + for (i = MECH_AES; i >= MECH_PLAIN; i--) + { + if (strstr (data, sasl_mechanisms[i]) != NULL) + { + serv->sasl_mech = i; + serv->retry_sasl = TRUE; + tcp_sendf (serv, "AUTHENTICATE %s\r\n", sasl_mechanisms[i]); + return; + } + } + + /* Nothing we support */ + goto sasl_abort; + } if (net->user && !(net->flags & FLAG_USE_GLOBAL)) user = net->user; @@ -1795,6 +1818,7 @@ inbound_sasl_authenticate (server *serv, char *data) #endif } +sasl_abort: if (pass == NULL) { /* something went wrong abort */ @@ -1815,6 +1839,9 @@ inbound_sasl_authenticate (server *serv, char *data) int inbound_sasl_error (server *serv) { + if (serv->retry_sasl && !serv->sent_saslauth) + return 1; + /* If server sent 904 before we sent password, * mech not support so fallback to next mech */ if (!serv->sent_saslauth && serv->sasl_mech != MECH_EXTERNAL && serv->sasl_mech != MECH_PLAIN)