summary refs log tree commit diff stats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/hexchat.h1
-rw-r--r--src/common/inbound.c27
2 files changed, 28 insertions, 0 deletions
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)