Merge pull request #183 from grawity/sasl-fail-throttle-v3
limit failed SASL authentication attempts
This commit is contained in:
commit
5eb8ce0679
2 changed files with 36 additions and 3 deletions
|
@ -285,6 +285,10 @@ struct LocalUser
|
||||||
char sasl_agent[IDLEN];
|
char sasl_agent[IDLEN];
|
||||||
unsigned char sasl_out;
|
unsigned char sasl_out;
|
||||||
unsigned char sasl_complete;
|
unsigned char sasl_complete;
|
||||||
|
|
||||||
|
unsigned int sasl_messages;
|
||||||
|
unsigned int sasl_failures;
|
||||||
|
time_t sasl_next_retry;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AuthClient
|
struct AuthClient
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "msg.h"
|
#include "msg.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
#include "numeric.h"
|
#include "numeric.h"
|
||||||
|
#include "reject.h"
|
||||||
#include "s_serv.h"
|
#include "s_serv.h"
|
||||||
#include "s_stats.h"
|
#include "s_stats.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
@ -130,6 +131,12 @@ m_authenticate(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *
|
||||||
if(!IsCapable(source_p, CLICAP_SASL))
|
if(!IsCapable(source_p, CLICAP_SASL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
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)
|
if(strlen(client_p->id) == 3)
|
||||||
{
|
{
|
||||||
exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
|
exit_client(client_p, client_p, client_p, "Mixing client and server protocol");
|
||||||
|
@ -223,17 +230,39 @@ me_sasl(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_
|
||||||
rb_strlcpy(target_p->localClient->sasl_agent, parv[1], IDLEN);
|
rb_strlcpy(target_p->localClient->sasl_agent, parv[1], IDLEN);
|
||||||
|
|
||||||
if(*parv[3] == 'C')
|
if(*parv[3] == 'C')
|
||||||
|
{
|
||||||
sendto_one(target_p, "AUTHENTICATE %s", parv[4]);
|
sendto_one(target_p, "AUTHENTICATE %s", parv[4]);
|
||||||
|
target_p->localClient->sasl_messages++;
|
||||||
|
}
|
||||||
else if(*parv[3] == 'D')
|
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);
|
sendto_one(target_p, form_str(ERR_SASLFAIL), me.name, EmptyString(target_p->name) ? "*" : target_p->name);
|
||||||
else if(*parv[4] == 'S') {
|
/* Failures with zero messages are just "unknown mechanism" errors; don't count those. */
|
||||||
|
if(target_p->localClient->sasl_messages > 0)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(*parv[4] == 'S')
|
||||||
|
{
|
||||||
sendto_one(target_p, form_str(RPL_SASLSUCCESS), me.name, EmptyString(target_p->name) ? "*" : target_p->name);
|
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;
|
target_p->localClient->sasl_complete = 1;
|
||||||
ServerStats.is_ssuc++;
|
ServerStats.is_ssuc++;
|
||||||
}
|
}
|
||||||
*target_p->localClient->sasl_agent = '\0'; /* Blank the stored agent so someone else can answer */
|
*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')
|
else if(*parv[3] == 'M')
|
||||||
sendto_one(target_p, form_str(RPL_SASLMECHS), me.name, EmptyString(target_p->name) ? "*" : target_p->name, parv[4]);
|
sendto_one(target_p, form_str(RPL_SASLMECHS), me.name, EmptyString(target_p->name) ? "*" : target_p->name, parv[4]);
|
||||||
|
|
Loading…
Reference in a new issue