]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_spanningtree/treesocket1.cpp
Wait longer before sending data on the connect than on the accept
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / treesocket1.cpp
index b0a7e32053dbd79de0e34c58473f342d868524b5..acc6c7fe2f4cf9fa22d3a18b848f1f928cfda414 100644 (file)
@@ -35,6 +35,7 @@
 
 /* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */
 
+
 /** Because most of the I/O gubbins are encapsulated within
  * InspSocket, we just call the superclass constructor for
  * most of the action, and append a few of our own values
@@ -75,7 +76,7 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, InspIRCd* SI, int newfd, cha
        if (Hook)
                InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
 
-       Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils));
+       Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1));
 }
 
 ServerState TreeSocket::GetLinkState()
@@ -101,7 +102,6 @@ const std::string& TreeSocket::GetOurChallenge()
 
 void TreeSocket::SetOurChallenge(const std::string &c)
 {
-       Instance->Log(DEBUG,"SetOurChallenge: "+c);
        this->ourchallenge = c;
 }
 
@@ -112,17 +112,29 @@ const std::string& TreeSocket::GetTheirChallenge()
 
 void TreeSocket::SetTheirChallenge(const std::string &c)
 {
-       Instance->Log(DEBUG,"SetTheirChallenge: "+c);
        this->theirchallenge = c;
 }
 
 std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)
 {
-       Instance->Log(DEBUG,"MakePass('"+password+"','"+challenge+"')");
+       /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
+        * suggesting the use of HMAC to secure the password against various attacks.
+        *
+        * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
+        *       HMAC challenge/response.
+        */
        Module* sha256 = Instance->FindModule("m_sha256.so");
-       if (sha256 && !challenge.empty())
+       if (Utils->ChallengeResponse && sha256 && !challenge.empty())
        {
-               /* sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) ) */
+               /* XXX: This is how HMAC is supposed to be done:
+                *
+                * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
+                *
+                * Note that we are encoding the hex hash, not the binary
+                * output of the hash which is slightly different to standard.
+                *
+                * Don't ask me why its always 0x5c and 0x36... it just is.
+                */
                std::string hmac1, hmac2;
 
                for (size_t n = 0; n < password.length(); n++)
@@ -131,20 +143,14 @@ std::string TreeSocket::MakePass(const std::string &password, const std::string
                        hmac2 += static_cast<char>(password[n] ^ 0x36);
                }
 
-               Instance->Log(DEBUG,"MakePass hmac1="+hmac1+" hmac="+hmac2);
-
                HashResetRequest(Utils->Creator, sha256).Send();
                hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send();
 
-               Instance->Log(DEBUG,"MakePass hmac1="+hmac1+" hmac="+hmac2);
-
                HashResetRequest(Utils->Creator, sha256).Send();
                std::string hmac = hmac1 + hmac2 + challenge;
                hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();
 
-               Instance->Log(DEBUG,"MakePass hmac="+hmac);
-
-               return hmac;
+               return "HMAC-SHA256:"+ hmac;
        }
        else if (!challenge.empty() && !sha256)
                Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
@@ -173,10 +179,9 @@ bool TreeSocket::OnConnected()
                                        InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
                                        this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2");
                                }
-                               else
-                                       this->SendCapabilities();
+                               this->OutboundPass = x->SendPass;
                                /* found who we're supposed to be connecting to, send the neccessary gubbins. */
-                               Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils));
+                               Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 2));
                                return true;
                        }
                }
@@ -260,9 +265,25 @@ std::string TreeSocket::MyCapabilities()
 
 std::string TreeSocket::RandString(unsigned int length)
 {
+       char* randombuf = new char[length+1];
        std::string out;
+       int fd = open("/dev/urandom", O_RDONLY, 0);
+
+       if (fd >= 0)
+       {
+               read(fd, randombuf, length);
+               close(fd);
+       }
+       else
+       {
+               for (unsigned int i = 0; i < length; i++)
+                       randombuf[i] = rand();
+       }
+
        for (unsigned int i = 0; i < length; i++)
-               out += static_cast<char>((rand() % 26) + 65);
+               out += static_cast<char>((randombuf[i] & 0x7F) | 0x21);
+
+       delete[] randombuf;
        return out;
 }
 
@@ -298,8 +319,15 @@ void TreeSocket::SendCapabilities()
 #ifdef SUPPORT_IP6LINKS
        ip6support = 1;
 #endif
-       this->SetOurChallenge(RandString(20));
-       this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+" CHALLENGE="+this->GetOurChallenge());
+       std::string extra;
+       /* Do we have sha256 available? If so, we send a challenge */
+       if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so")))
+       {
+               this->SetOurChallenge(RandString(20));
+               extra = " CHALLENGE=" + this->GetOurChallenge();
+       }
+
+       this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra);
 
        this->WriteLine("CAPAB END");
 }
@@ -410,10 +438,20 @@ bool TreeSocket::Capab(const std::deque<std::string> &params)
 
                /* Challenge response, store their challenge for our password */
                std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE");
-               if (n != this->CapKeys.end())
+               if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so")))
                {
                        /* Challenge-response is on now */
                        this->SetTheirChallenge(n->second);
+                       if (!this->GetOurChallenge().empty() && (this->LinkState == CONNECTING))
+                       {
+                               this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
+                       }
+               }
+               else
+               {
+                       /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
+                       if (this->LinkState == CONNECTING)
+                               this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc);
                }
 
                if (reason.length())
@@ -1257,11 +1295,10 @@ void TreeSocket::SendUsers(TreeServer* Current)
  */
 void TreeSocket::DoBurst(TreeServer* s)
 {
+       std::string name = s->GetName();
        std::string burst = "BURST "+ConvToStr(Instance->Time(true));
        std::string endburst = "ENDBURST";
-       // Because by the end of the netburst, it  could be gone!
-       std::string name = s->GetName();
-       this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2"+name+"\2.");
+       this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response");
        this->WriteLine(burst);
        /* send our version string */
        this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString());