From 37289346cda823ee0e1b30fce8d46dd4a31bf694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= Date: Fri, 13 Feb 2015 20:13:06 +0200 Subject: [PATCH 1/3] m_sasl: temporarily reject clients after many failed attempts --- include/client.h | 1 + modules/m_sasl.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/client.h b/include/client.h index a97b67bd0..c97bf8ab7 100644 --- a/include/client.h +++ b/include/client.h @@ -285,6 +285,7 @@ struct LocalUser char sasl_agent[IDLEN]; unsigned char sasl_out; unsigned char sasl_complete; + unsigned short sasl_messages; }; struct AuthClient diff --git a/modules/m_sasl.c b/modules/m_sasl.c index 23a5e313e..b06ce6922 100644 --- a/modules/m_sasl.c +++ b/modules/m_sasl.c @@ -35,6 +35,7 @@ #include "msg.h" #include "modules.h" #include "numeric.h" +#include "reject.h" #include "s_serv.h" #include "s_stats.h" #include "string.h" @@ -223,17 +224,30 @@ me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ rb_strlcpy(target_p->localClient->sasl_agent, parv[1], IDLEN); if(*parv[3] == 'C') + { sendto_one(target_p, "AUTHENTICATE %s", parv[4]); + target_p->localClient->sasl_messages++; + } else if(*parv[3] == 'D') { - if(*parv[4] == 'F') + if(*parv[4] == 'F') { sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name); + if (target_p->localClient->sasl_messages > 0) + { + if (throttle_add((struct sockaddr*)&target_p->localClient->ip)) + { + exit_client(target_p, target_p, &me, "Too many failed authentication attempts"); + return; + } + } + } else if(*parv[4] == 'S') { sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name); target_p->localClient->sasl_complete = 1; ServerStats.is_ssuc++; } *target_p->localClient->sasl_agent = '\0'; /* Blank the stored agent so someone else can answer */ + target_p->localClient->sasl_messages = 0; } else if(*parv[3] == 'M') sendto_one(target_p, form_str(RPL_SASLMECHS), me.name, EmptyString(target_p->name) ? "*" : target_p->name, parv[4]); From 834579cecdab4eae48ca381922e503cdb9c5eb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= Date: Mon, 11 Apr 2016 20:12:31 +0300 Subject: [PATCH 2/3] m_sasl: fix coding style --- modules/m_sasl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/m_sasl.c b/modules/m_sasl.c index b06ce6922..4d257ab89 100644 --- a/modules/m_sasl.c +++ b/modules/m_sasl.c @@ -230,18 +230,20 @@ me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ } else if(*parv[3] == 'D') { - if(*parv[4] == 'F') { + if(*parv[4] == 'F') + { sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name); - if (target_p->localClient->sasl_messages > 0) + if(target_p->localClient->sasl_messages > 0) { - if (throttle_add((struct sockaddr*)&target_p->localClient->ip)) + if(throttle_add((struct sockaddr*)&target_p->localClient->ip)) { exit_client(target_p, target_p, &me, "Too many failed authentication attempts"); return; } } } - else if(*parv[4] == 'S') { + else if(*parv[4] == 'S') + { sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name); target_p->localClient->sasl_complete = 1; ServerStats.is_ssuc++; From 9d07a42d7a2377eb59150dd0316a884855cbeb2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mantas=20Mikul=C4=97nas?= Date: Mon, 11 Apr 2016 21:38:43 +0300 Subject: [PATCH 3/3] m_sasl: rate-limit SASL REAUTH usage --- include/client.h | 5 ++++- modules/m_sasl.c | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/client.h b/include/client.h index c97bf8ab7..cfc55ceee 100644 --- a/include/client.h +++ b/include/client.h @@ -285,7 +285,10 @@ struct LocalUser char sasl_agent[IDLEN]; unsigned char sasl_out; unsigned char sasl_complete; - unsigned short sasl_messages; + + unsigned int sasl_messages; + unsigned int sasl_failures; + time_t sasl_next_retry; }; struct AuthClient diff --git a/modules/m_sasl.c b/modules/m_sasl.c index 4d257ab89..470832cb8 100644 --- a/modules/m_sasl.c +++ b/modules/m_sasl.c @@ -131,14 +131,20 @@ m_authenticate(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client * if(!IsCapable(source_p, CLICAP_SASL)) return; - if (strlen(client_p->id) == 3) + if(source_p->localClient->sasl_next_retry > rb_current_time()) + { + sendto_one(source_p, form_str(RPL_LOAD2HI), me.name, EmptyString(source_p->name) ? "*" : source_p->name, msgbuf_p->cmd); + return; + } + + if(strlen(client_p->id) == 3) { exit_client(client_p, client_p, client_p, "Mixing client and server protocol"); return; } saslserv_p = find_named_client(ConfigFileEntry.sasl_service); - if (saslserv_p == NULL || !IsService(saslserv_p)) + if(saslserv_p == NULL || !IsService(saslserv_p)) { sendto_one(source_p, form_str(ERR_SASLABORTED), me.name, EmptyString(source_p->name) ? "*" : source_p->name); return; @@ -233,9 +239,15 @@ me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ if(*parv[4] == 'F') { sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name); + /* Failures with zero messages are just "unknown mechanism" errors; don't count those. */ if(target_p->localClient->sasl_messages > 0) { - if(throttle_add((struct sockaddr*)&target_p->localClient->ip)) + if(*target_p->name) + { + target_p->localClient->sasl_failures++; + target_p->localClient->sasl_next_retry = rb_current_time() + (1 << MIN(target_p->localClient->sasl_failures + 5, 13)); + } + else if(throttle_add((struct sockaddr*)&target_p->localClient->ip)) { exit_client(target_p, target_p, &me, "Too many failed authentication attempts"); return; @@ -245,6 +257,7 @@ me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ else if(*parv[4] == 'S') { sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name); + target_p->localClient->sasl_failures = 0; target_p->localClient->sasl_complete = 1; ServerStats.is_ssuc++; }