]> jfr.im git - solanum.git/blobdiff - modules/m_sasl.c
ssld: avoid clang static analysis warning
[solanum.git] / modules / m_sasl.c
index 4d257ab895740de232ad1c4490fc0685865f998d..80e21661aabc2fd0c408c8f2ef313729061d744a 100644 (file)
@@ -131,14 +131,26 @@ 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;
        }
 
+       if (*parv[1] == ':' || strchr(parv[1], ' '))
+       {
+               exit_client(client_p, client_p, client_p, "Malformed AUTHENTICATE");
+               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;
@@ -159,7 +171,7 @@ m_authenticate(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *
        if(!*source_p->id)
        {
                /* Allocate a UID. */
-               strcpy(source_p->id, generate_uid());
+               rb_strlcpy(source_p->id, generate_uid(), sizeof(source_p->id));
                add_to_id_hash(source_p->id, source_p);
        }
 
@@ -233,9 +245,19 @@ 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)
+                               {
+                                       /* Allow 2 tries before rate-limiting as some clients try EXTERNAL
+                                        * then PLAIN right after it if the auth failed, causing the client to be
+                                        * rate-limited immediately and not being able to login with SASL.
+                                        */
+                                       if (target_p->localClient->sasl_failures++ > 0)
+                                               target_p->localClient->sasl_next_retry = rb_current_time() + (1 << MIN(target_p->localClient->sasl_failures + 1, 8));
+                               }
+                               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 +267,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++;
                }