From 33318dd6fbc2fa38ccf16ca90a95666f28d860b3 Mon Sep 17 00:00:00 2001 From: danieldg Date: Fri, 15 Jan 2010 19:46:01 +0000 Subject: Add CAPAB CHANMODES, CAPAB USERMODES to verify matching of modes by name, not just by letter git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@12262 e03df62e-2008-0410-955e-edbf42e46eb7 --- src/modules/m_spanningtree/capab.cpp | 130 +++++++++++++++++++++-------- src/modules/m_spanningtree/hmac.cpp | 18 ++-- src/modules/m_spanningtree/netburst.cpp | 4 +- src/modules/m_spanningtree/treesocket.h | 27 +++--- src/modules/m_spanningtree/treesocket1.cpp | 18 ++-- 5 files changed, 134 insertions(+), 63 deletions(-) diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp index de97b6c70..e5d63ab22 100644 --- a/src/modules/m_spanningtree/capab.cpp +++ b/src/modules/m_spanningtree/capab.cpp @@ -49,15 +49,33 @@ std::string TreeSocket::MyModules(int filter) return capabilities; } +static std::string BuildModeList(ModeType type) +{ + std::string line; + for(char c='A'; c <= 'z'; c++) + { + ModeHandler* mh = ServerInstance->Modes->FindMode(c, type); + if (mh) + { + if (!line.empty()) + line.push_back(','); + line.append(mh->name); + line.push_back('='); + line.push_back(c); + } + } + return line; +} + void TreeSocket::SendCapabilities(int phase) { - if (capab_phase >= phase) + if (capab->capab_phase >= phase) return; - if (capab_phase < 1 && phase >= 1) + if (capab->capab_phase < 1 && phase >= 1) WriteLine("CAPAB START " + ConvToStr(ProtocolVersion)); - capab_phase = phase; + capab->capab_phase = phase; if (phase < 2) return; @@ -99,6 +117,13 @@ void TreeSocket::SendCapabilities(int phase) if (line != "CAPAB MODSUPPORT ") this->WriteLine(line); + line = "CAPAB CHANMODES " + BuildModeList(MODETYPE_CHANNEL); + if (line != "CAPAB CHANMODES ") + this->WriteLine(line); + + line = "CAPAB USERMODES " + BuildModeList(MODETYPE_USER); + if (line != "CAPAB USERMODES ") + this->WriteLine(line); int ip6 = 0; #ifdef IPV6 @@ -173,9 +198,9 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } if (params[0] == "START") { - ModuleList.clear(); - OptModuleList.clear(); - CapKeys.clear(); + capab->ModuleList.clear(); + capab->OptModuleList.clear(); + capab->CapKeys.clear(); if (params.size() > 1) proto_version = atoi(params[1].c_str()); SendCapabilities(2); @@ -184,10 +209,10 @@ bool TreeSocket::Capab(const parameterlist ¶ms) { std::string reason; /* Compare ModuleList and check CapKeys */ - if ((this->ModuleList != this->MyModules(VF_COMMON)) && (this->ModuleList.length())) + if ((this->capab->ModuleList != this->MyModules(VF_COMMON)) && (this->capab->ModuleList.length())) { - std::string diffIneed = ListDifference(this->ModuleList, this->MyModules(VF_COMMON)); - std::string diffUneed = ListDifference(this->MyModules(VF_COMMON), this->ModuleList); + std::string diffIneed = ListDifference(this->capab->ModuleList, this->MyModules(VF_COMMON)); + std::string diffUneed = ListDifference(this->MyModules(VF_COMMON), this->capab->ModuleList); if (diffIneed.length() == 0 && diffUneed.length() == 0) { reason = "Module list in CAPAB is not alphabetically ordered, cannot compare lists."; @@ -203,10 +228,10 @@ bool TreeSocket::Capab(const parameterlist ¶ms) this->SendError("CAPAB negotiation failed: "+reason); return false; } - if (this->OptModuleList != this->MyModules(VF_OPTCOMMON) && this->OptModuleList.length()) + if (this->capab->OptModuleList != this->MyModules(VF_OPTCOMMON) && this->capab->OptModuleList.length()) { - std::string diffIneed = ListDifference(this->OptModuleList, this->MyModules(VF_OPTCOMMON)); - std::string diffUneed = ListDifference(this->MyModules(VF_OPTCOMMON), this->OptModuleList); + std::string diffIneed = ListDifference(this->capab->OptModuleList, this->MyModules(VF_OPTCOMMON)); + std::string diffUneed = ListDifference(this->MyModules(VF_OPTCOMMON), this->capab->OptModuleList); if (diffIneed.length() == 0 && diffUneed.length() == 0) { reason = "Optional Module list in CAPAB is not alphabetically ordered, cannot compare lists."; @@ -230,13 +255,13 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } } - if (this->CapKeys.find("PROTOCOL") == this->CapKeys.end()) + if (this->capab->CapKeys.find("PROTOCOL") == this->capab->CapKeys.end()) { reason = "Protocol version not specified"; } else { - proto_version = atoi(CapKeys.find("PROTOCOL")->second.c_str()); + proto_version = atoi(capab->CapKeys.find("PROTOCOL")->second.c_str()); if (proto_version < MinCompatProtocol) { reason = "Server is using protocol version " + ConvToStr(proto_version) + @@ -245,26 +270,57 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } } - if(this->CapKeys.find("PREFIX") != this->CapKeys.end() && this->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) + if(this->capab->CapKeys.find("PREFIX") != this->capab->CapKeys.end() && this->capab->CapKeys.find("PREFIX")->second != ServerInstance->Modes->BuildPrefixes()) reason = "One or more of the prefixes on the remote server are invalid on this server."; - if(this->CapKeys.find("CHANMODES") != this->CapKeys.end() && this->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MASK_CHANNEL)) - reason = "One or more of the channel modes on the remote server are invalid on this server."; - - if(this->CapKeys.find("USERMODES") != this->CapKeys.end() && this->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MASK_USER)) - reason = "One or more of the user modes on the remote server are invalid on this server."; + if (!capab->ChanModes.empty()) + { + if (capab->ChanModes != BuildModeList(MODETYPE_CHANNEL)) + { + std::string diffIneed = ListDifference(capab->ChanModes, BuildModeList(MODETYPE_CHANNEL)); + std::string diffUneed = ListDifference(BuildModeList(MODETYPE_CHANNEL), capab->ChanModes); + reason = "Channel modes not matched on these servers."; + if (diffIneed.length()) + reason += " Not loaded here:" + diffIneed; + if (diffUneed.length()) + reason += " Not loaded there:" + diffUneed; + } + } + else if (this->capab->CapKeys.find("CHANMODES") != this->capab->CapKeys.end()) + { + if (this->capab->CapKeys.find("CHANMODES")->second != ServerInstance->Modes->GiveModeList(MASK_CHANNEL)) + reason = "One or more of the channel modes on the remote server are invalid on this server."; + } + if (!capab->UserModes.empty()) + { + if (capab->UserModes != BuildModeList(MODETYPE_USER)) + { + std::string diffIneed = ListDifference(capab->UserModes, BuildModeList(MODETYPE_USER)); + std::string diffUneed = ListDifference(BuildModeList(MODETYPE_USER), capab->UserModes); + reason = "User modes not matched on these servers."; + if (diffIneed.length()) + reason += " Not loaded here:" + diffIneed; + if (diffUneed.length()) + reason += " Not loaded there:" + diffUneed; + } + } + else if (this->capab->CapKeys.find("USERMODES") != this->capab->CapKeys.end()) + { + if (this->capab->CapKeys.find("USERMODES")->second != ServerInstance->Modes->GiveModeList(MASK_USER)) + reason = "One or more of the user modes on the remote server are invalid on this server."; + } /* Challenge response, store their challenge for our password */ - std::map::iterator n = this->CapKeys.find("CHALLENGE"); - if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (ServerInstance->Modules->Find("m_sha256.so"))) + std::map::iterator n = this->capab->CapKeys.find("CHALLENGE"); + if (Utils->ChallengeResponse && (n != this->capab->CapKeys.end()) && (ServerInstance->Modules->Find("m_sha256.so"))) { /* Challenge-response is on now */ this->SetTheirChallenge(n->second); if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) { this->SendCapabilities(2); - this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 "+ + this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+this->MakePass(capab->OutboundPass, this->GetTheirChallenge())+" 0 "+ ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } @@ -274,7 +330,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) if (this->LinkState == CONNECTING) { this->SendCapabilities(2); - this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+OutboundPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); + this->WriteLine(std::string("SERVER ")+ServerInstance->Config->ServerName+" "+capab->OutboundPass+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc); } } @@ -286,28 +342,36 @@ bool TreeSocket::Capab(const parameterlist ¶ms) } else if ((params[0] == "MODULES") && (params.size() == 2)) { - if (!this->ModuleList.length()) + if (!this->capab->ModuleList.length()) { - this->ModuleList.append(params[1]); + this->capab->ModuleList.append(params[1]); } else { - this->ModuleList.append(","); - this->ModuleList.append(params[1]); + this->capab->ModuleList.append(","); + this->capab->ModuleList.append(params[1]); } } else if ((params[0] == "MODSUPPORT") && (params.size() == 2)) { - if (!this->OptModuleList.length()) + if (!this->capab->OptModuleList.length()) { - this->OptModuleList.append(params[1]); + this->capab->OptModuleList.append(params[1]); } else { - this->OptModuleList.append(","); - this->OptModuleList.append(params[1]); + this->capab->OptModuleList.append(","); + this->capab->OptModuleList.append(params[1]); } } + else if ((params[0] == "CHANMODES") && (params.size() == 2)) + { + capab->ChanModes = params[1]; + } + else if ((params[0] == "USERMODES") && (params.size() == 2)) + { + capab->UserModes = params[1]; + } else if ((params[0] == "CAPABILITIES") && (params.size() == 2)) { irc::tokenstream capabs(params[1]); @@ -321,7 +385,7 @@ bool TreeSocket::Capab(const parameterlist ¶ms) { std::string var = item.substr(0, equals); std::string value = item.substr(equals+1, item.length()); - CapKeys[var] = value; + capab->CapKeys[var] = value; } } } diff --git a/src/modules/m_spanningtree/hmac.cpp b/src/modules/m_spanningtree/hmac.cpp index 573dada4f..172883f3f 100644 --- a/src/modules/m_spanningtree/hmac.cpp +++ b/src/modules/m_spanningtree/hmac.cpp @@ -29,22 +29,22 @@ const std::string& TreeSocket::GetOurChallenge() { - return this->ourchallenge; + return capab->ourchallenge; } void TreeSocket::SetOurChallenge(const std::string &c) { - this->ourchallenge = c; + capab->ourchallenge = c; } const std::string& TreeSocket::GetTheirChallenge() { - return this->theirchallenge; + return capab->theirchallenge; } void TreeSocket::SetTheirChallenge(const std::string &c) { - this->theirchallenge = c; + capab->theirchallenge = c; } std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge) @@ -130,8 +130,8 @@ std::string TreeSocket::RandString(unsigned int ilength) bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) { - this->auth_fingerprint = !link.Fingerprint.empty(); - this->auth_challenge = !ourchallenge.empty() && !theirchallenge.empty(); + capab->auth_fingerprint = !link.Fingerprint.empty(); + capab->auth_challenge = !capab->ourchallenge.empty() && !capab->theirchallenge.empty(); std::string fp; if (GetIOHook()) @@ -143,9 +143,9 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) } } - if (auth_challenge) + if (capab->auth_challenge) { - std::string our_hmac = MakePass(link.RecvPass, ourchallenge); + std::string our_hmac = MakePass(link.RecvPass, capab->ourchallenge); /* Straight string compare of hashes */ if (our_hmac != theirs) @@ -158,7 +158,7 @@ bool TreeSocket::ComparePass(const Link& link, const std::string &theirs) return false; } - if (auth_fingerprint) + if (capab->auth_fingerprint) { /* Require fingerprint to exist and match */ if (link.Fingerprint != fp) diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index ca87b09f9..0e2ae2bf8 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -34,8 +34,8 @@ void TreeSocket::DoBurst(TreeServer* s) std::string endburst = ":" + ServerInstance->Config->GetSID() + " ENDBURST"; ServerInstance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s%s).", name.c_str(), - this->auth_fingerprint ? "SSL Fingerprint and " : "", - this->auth_challenge ? "challenge-response" : "plaintext password"); + capab->auth_fingerprint ? "SSL Fingerprint and " : "", + capab->auth_challenge ? "challenge-response" : "plaintext password"); this->CleanNegotiationInfo(); this->WriteLine(burst); /* send our version string */ diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index 773a6cd13..7bbaba050 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -54,6 +54,21 @@ */ enum ServerState { CONNECTING, WAIT_AUTH_1, WAIT_AUTH_2, CONNECTED }; +struct CapabData +{ + std::string ModuleList; /* Required module list of other server from CAPAB */ + std::string OptModuleList; /* Optional module list of other server from CAPAB */ + std::string ChanModes; + std::string UserModes; + std::map CapKeys; /* CAPAB keys from other server */ + std::string ourchallenge; /* Challenge sent for challenge/response */ + std::string theirchallenge; /* Challenge recv for challenge/response */ + std::string OutboundPass; /* Outbound password */ + int capab_phase; /* Have sent CAPAB already */ + bool auth_fingerprint; /* Did we auth using SSL fingerprint */ + bool auth_challenge; /* Did we auth using challenge/response */ +}; + /** Every SERVER connection inbound or outbound is represented by * an object of type TreeSocket. * TreeSockets, being inherited from BufferedSocket, can be tied into @@ -73,20 +88,12 @@ class TreeSocket : public BufferedSocket std::string InboundServerName; /* Server name sent to us by other side */ std::string InboundDescription; /* Server description (GECOS) sent to us by the other side */ std::string InboundSID; /* Server ID sent to us by the other side */ + std::string IP; + CapabData* capab; int num_lost_users; /* Users lost in split */ int num_lost_servers; /* Servers lost in split */ time_t NextPing; /* Time when we are due to ping this server */ bool LastPingWasGood; /* Responded to last ping we sent? */ - std::string IP; - std::string ModuleList; /* Required module list of other server from CAPAB */ - std::string OptModuleList; /* Optional module list of other server from CAPAB */ - std::map CapKeys; /* CAPAB keys from other server */ - std::string ourchallenge; /* Challenge sent for challenge/response */ - std::string theirchallenge; /* Challenge recv for challenge/response */ - std::string OutboundPass; /* Outbound password */ - int capab_phase; /* Have sent CAPAB already */ - bool auth_fingerprint; /* Did we auth using SSL fingerprint */ - bool auth_challenge; /* Did we auth using challenge/response */ int proto_version; /* Remote protocol version */ public: reference myautoconnect; /* Autoconnect used to cause this connection, if any */ diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index c96bf3bc9..71cca66c4 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -35,7 +35,8 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, const std::string& shost, in { age = ServerInstance->Time(); myhost = ServerName; - capab_phase = 0; + capab = new CapabData; + capab->capab_phase = 0; proto_version = 0; LinkState = CONNECTING; if (!hook.empty()) @@ -60,10 +61,11 @@ TreeSocket::TreeSocket(SpanningTreeUtilities* Util, const std::string& shost, in TreeSocket::TreeSocket(SpanningTreeUtilities* Util, int newfd, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) : BufferedSocket(newfd), Utils(Util) { + capab = new CapabData; IP = client->addr(); age = ServerInstance->Time(); LinkState = WAIT_AUTH_1; - capab_phase = 0; + capab->capab_phase = 0; proto_version = 0; myhost = "inbound from " + IP; @@ -82,12 +84,8 @@ ServerState TreeSocket::GetLinkState() void TreeSocket::CleanNegotiationInfo() { - ModuleList.clear(); - OptModuleList.clear(); - CapKeys.clear(); - ourchallenge.clear(); - theirchallenge.clear(); - OutboundPass.clear(); + delete capab; + capab = NULL; } CullResult TreeSocket::cull() @@ -100,6 +98,8 @@ CullResult TreeSocket::cull() TreeSocket::~TreeSocket() { + if (capab) + delete capab; } /** When an outbound connection finishes connecting, we receive @@ -119,7 +119,7 @@ void TreeSocket::OnConnected() if (x->Name == this->myhost) { ServerInstance->SNO->WriteGlobalSno('l', "Connection to \2%s\2[%s] started.", myhost.c_str(), (x->HiddenFromStats ? "" : this->IP.c_str())); - this->OutboundPass = x->SendPass; + capab->OutboundPass = x->SendPass; this->SendCapabilities(1); return; } -- cgit v1.2.3