From 889d521e05f2e922683d48c74eb00290e7a2f548 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 17 Jul 2024 00:06:50 +0100 Subject: Shuffle the modules about a bit. --- src/modules/m_spanningtree/capab.cpp | 643 ----------------------------------- 1 file changed, 643 deletions(-) delete mode 100644 src/modules/m_spanningtree/capab.cpp (limited to 'src/modules/m_spanningtree/capab.cpp') diff --git a/src/modules/m_spanningtree/capab.cpp b/src/modules/m_spanningtree/capab.cpp deleted file mode 100644 index f3381b1c3..000000000 --- a/src/modules/m_spanningtree/capab.cpp +++ /dev/null @@ -1,643 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2017-2024 Sadie Powell - * Copyright (C) 2013-2016 Attila Molnar - * Copyright (C) 2012 Robby - * Copyright (C) 2009-2010 Daniel De Graaf - * Copyright (C) 2008 Robin Burchell - * Copyright (C) 2008 Craig Edwards - * - * This file is part of InspIRCd. InspIRCd is free software: you can - * redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include "inspircd.h" -#include "dynamic.h" -#include "modules/extban.h" -#include "utility/map.h" - -#include "treeserver.h" -#include "utils.h" -#include "link.h" -#include "main.h" - -namespace -{ - // A map which holds the difference between local and remote tokens. - typedef std::map, std::optional>, irc::insensitive_swo> TokenDiff; - - // Builds a list of the local modules with the specified property. - CapabData::ModuleMap BuildModuleList(ModuleFlags property, uint16_t protocol) - { - CapabData::ModuleMap modules; - for (const auto& [name, module] : ServerInstance->Modules.GetModules()) - { - if (!(module->properties & property)) - continue; - - std::string modname; - size_t endpos = name.length() - strlen(DLL_EXTENSION); - if (protocol <= PROTO_INSPIRCD_3) - { - // Replace m_foo.dylib with m_foo.so - modname.append(name.substr(0, endpos)).append(".so"); - - // Handle renamed modules. - if (insp::equalsci(modname, "m_cloak.so") && ServerInstance->Modules.Find("cloak_md5")) - modname = "m_cloaking.so"; - else if (insp::equalsci(modname, "m_realnameban.so")) - modname = "m_gecosban.so"; - else if (insp::equalsci(modname, "m_account.so") && ServerInstance->Modules.Find("services")) - modname = "m_services_account.so"; - else if (insp::equalsci(modname, "m_services.so")) - { - modules["m_svshold.so"]; - modules["m_topiclock.so"]; - continue; - } - - // Handle modules with changed properties. - else if (insp::equalsci(modname, "m_globops.so")) - continue; // This module was made VF_OPTCOMMON in v4. - } - else - { - // Replace m_foo.dylib with foo - size_t startpos = name.compare(0, 2, "m_", 2) ? 0 : 2; - modname.assign(name.substr(startpos, endpos - startpos)); - } - - modules[modname] = SpanningTreeUtilities::BuildLinkString(protocol, module); - } - return modules; - } - - // Compares the module data sent by a remote server to that of the local server. - bool CompareModuleData(Module* mod, const Module::LinkData& otherdata, std::ostringstream& diffconfig) - { - Module::LinkDataDiff datadiff; - mod->CompareLinkData(otherdata, datadiff); - if (!datadiff.empty()) - { - diffconfig << ' ' << ModuleManager::ShrinkModName(mod->ModuleFile) << " ("; - bool first = true; - for (const auto& [key, values] : datadiff) - { - // Keys are separated by commas. - if (!first) - diffconfig << ", "; - first = false; - - diffconfig << key; - if (values.first && values.second) - { - // Exists on both but with a different value. - diffconfig << " set to " << *values.first << " here and " << *values.second << " there"; - } - else if (values.first && !values.second) - { - // Only exists on the local server. - diffconfig << " only set here"; - } - else if (!values.first && values.second) - { - // Only exists on the remote server. - diffconfig << " only set there"; - } - } - - diffconfig << ')'; - return false; - } - - return true; - } - - // Compares the lists of module on a remote v3 server to the local server. - bool CompareModulesOld(ModuleFlags property, const CapabData::ModuleMap& remote, std::ostringstream& diffconfig, - std::ostringstream& localmissing, std::ostringstream& remotemissing) - { - // Retrieve the local module list and compare to the remote. - CapabData::ModuleMap mymodules = BuildModuleList(property, PROTO_INSPIRCD_3); - TokenDiff modulediff; - insp::map::difference(mymodules, remote, modulediff); - - for (const auto& [module, values] : modulediff) - { - if (values.first && values.second) - { - // Exists on both but with different link data. - diffconfig << ' ' << module << " (" << *values.first << " here, " << *values.second << " there)"; - } - else if (values.first && !values.second) - { - // Only exists on the local server. - remotemissing << ' ' << module; - } - else if (!values.first && values.second) - { - // Only exists on the remote server. - localmissing << ' ' << module; - } - } - - return modulediff.empty(); - } - - // Compares the lists of module on a remote v4+ server to the local server. - bool CompareModulesNew(ModuleFlags property, const CapabData::ModuleMap& remote, std::ostringstream& diffconfig, - std::ostringstream& localmissing, std::ostringstream& remotemissing) - { - // Retrieve the local module list. - bool okay = true; - ModuleManager::ModuleMap local; - for (const auto& [name, module] : ServerInstance->Modules.GetModules()) - { - if (module->properties & property) - local[ModuleManager::ShrinkModName(name)] = module; - } - - for (const auto& [name, linkdata] : remote) - { - auto moditer = local.find(name); - if (moditer == local.end()) - { - // Only exists on the remote server. - localmissing << ' ' << name; - okay = false; - continue; - } - - // Parse the remote link data. - Module::LinkData otherdata; - irc::sepstream datastream(linkdata, '&'); - for (std::string datapair; datastream.GetToken(datapair); ) - { - size_t split = datapair.find('='); - if (split == std::string::npos) - otherdata.emplace(datapair, ""); - else - otherdata.emplace(datapair.substr(0, split), Percent::Decode(datapair.substr(split + 1))); - } - - // Compare the link data. - if (!CompareModuleData(moditer->second, otherdata, diffconfig)) - okay = false; - local.erase(moditer); - } - - for (const auto& [name, _] : local) - { - // Only exists on the local server. - remotemissing << ' ' << name; - okay = false; - } - - return okay; - } - - // Compares the lists of module on a remote server to the local server. - bool CompareModules(ModuleFlags property, uint16_t protocol, std::optional& remote, - std::ostringstream& out) - { - // If the remote didn't send a module list then don't compare. - if (!remote) - return true; - - bool okay; - std::ostringstream diffconfig; - std::ostringstream localmissing; - std::ostringstream remotemissing; - if (protocol <= PROTO_INSPIRCD_3) - okay = CompareModulesOld(property, *remote, diffconfig, localmissing, remotemissing); - else - okay = CompareModulesNew(property, *remote, diffconfig, localmissing, remotemissing); - - if (!diffconfig.str().empty()) - out << " Loaded on both with different config:" << diffconfig.str() << '.'; - if (!localmissing.str().empty()) - out << " Not loaded on the local server:" << localmissing.str() << '.'; - if (!remotemissing.str().empty()) - out << " Not loaded on the remote server:" << remotemissing.str() << '.'; - - return okay; - } - - // Generates a module list in the format "m_foo.so=bar m_bar.so=baz". - std::string FormatModules(ModuleFlags property, uint16_t protocol) - { - std::ostringstream modules; - CapabData::ModuleMap mymodules = BuildModuleList(property, protocol); - for (const auto& [module, linkdata] : mymodules) - { - modules << module; - if (!linkdata.empty()) - modules << '=' << linkdata; - modules << ' '; - } - return modules.str(); - } - - // Parses a module list in the format "m_foo.so=bar m_bar.so=baz" to a map. - void ParseModules(const std::string& modlist, std::optional& out) - { - CapabData::ModuleMap& map = out ? *out : out.emplace(); - irc::spacesepstream modstream(modlist); - for (std::string mod; modstream.GetToken(mod); ) - { - size_t split = mod.find('='); - if (split == std::string::npos) - map.emplace(mod, ""); - else - map.emplace(mod.substr(0, split), mod.substr(split + 1)); - } - } -} - -std::string TreeSocket::BuildModeList(ModeType mtype) -{ - std::vector modes; - for (const auto& [_, mh] : ServerInstance->Modes.GetModes(mtype)) - { - const PrefixMode* const pm = mh->IsPrefixMode(); - std::string mdesc; - if (pm) - mdesc.append("prefix:").append(ConvToStr(pm->GetPrefixRank())).push_back(':'); - else if (mh->IsListMode()) - mdesc.append("list:"); - else if (mh->NeedsParam(true)) - mdesc.append(mh->NeedsParam(false) ? "param:" : "param-set:"); - else - mdesc.append("simple:"); - mdesc.append(mh->name); - mdesc.push_back('='); - if (pm) - { - if (pm->GetPrefix()) - mdesc.push_back(pm->GetPrefix()); - } - mdesc.push_back(mh->GetModeChar()); - modes.push_back(mdesc); - } - std::sort(modes.begin(), modes.end()); - return insp::join(modes); -} - -bool TreeSocket::BuildExtBanList(std::string& out) -{ - ExtBan::ManagerRef extbanmgr(Utils->Creator); - if (!extbanmgr) - return false; - - const ExtBan::Manager::LetterMap& extbans = extbanmgr->GetLetterMap(); - for (ExtBan::Manager::LetterMap::const_iterator iter = extbans.begin(); iter != extbans.end(); ++iter) - { - if (iter != extbans.begin()) - out.push_back(' '); - - const ExtBan::Base* extban = iter->second; - switch (extban->GetType()) - { - case ExtBan::Type::ACTING: - out.append("acting:"); - break; - case ExtBan::Type::MATCHING: - out.append("matching:"); - break; - } - - out.append(extban->GetName()) - .append("=") - .push_back(extban->GetLetter()); - } - return true; -} - -void TreeSocket::SendCapabilities(int phase) -{ - if (capab->capab_phase >= phase) - return; - - if (capab->capab_phase < 1 && phase >= 1) - WriteLine("CAPAB START " + ConvToStr(PROTO_NEWEST)); - - capab->capab_phase = phase; - if (phase < 2) - return; - - WriteLine("CAPAB MODULES :" + FormatModules(VF_COMMON, proto_version)); - WriteLine("CAPAB MODSUPPORT :" + FormatModules(VF_OPTCOMMON, proto_version)); - WriteLine("CAPAB CHANMODES :" + BuildModeList(MODETYPE_CHANNEL)); - WriteLine("CAPAB USERMODES :" + BuildModeList(MODETYPE_USER)); - - std::unordered_map capabilities = { - { "CASEMAPPING", ServerInstance->Config->CaseMapping }, - { "MAXAWAY", ConvToStr(ServerInstance->Config->Limits.MaxAway) }, - { "MAXCHANNEL", ConvToStr(ServerInstance->Config->Limits.MaxChannel) }, - { "MAXHOST", ConvToStr(ServerInstance->Config->Limits.MaxHost) }, - { "MAXKICK", ConvToStr(ServerInstance->Config->Limits.MaxKick) }, - { "MAXLINE", ConvToStr(ServerInstance->Config->Limits.MaxLine) }, - { "MAXMODES", ConvToStr(ServerInstance->Config->Limits.MaxModes) }, - { "MAXNICK", ConvToStr(ServerInstance->Config->Limits.MaxNick) }, - { "MAXQUIT", ConvToStr(ServerInstance->Config->Limits.MaxQuit) }, - { "MAXREAL", ConvToStr(ServerInstance->Config->Limits.MaxReal) }, - { "MAXTOPIC", ConvToStr(ServerInstance->Config->Limits.MaxTopic) }, - { "MAXUSER", ConvToStr(ServerInstance->Config->Limits.MaxUser) }, - }; - - if (proto_version <= PROTO_INSPIRCD_3) - { - // 1205 HACK: Allow services to know what extbans exist. - ExtBan::ManagerRef extbanmgr(Utils->Creator); - if (extbanmgr) - { - std::string extbans; - for (const auto& [extban, _] : extbanmgr->GetLetterMap()) - extbans.push_back(extban); - - if (!extbans.empty()) - capabilities["EXTBANS"] = extbans; - } - - // These have been renamed in the 1206 protocol. - capabilities["CHANMAX"] = capabilities["MAXCHANNEL"]; - capabilities["IDENTMAX"] = capabilities["MAXUSER"]; - capabilities["NICKMAX"] = capabilities["MAXNICK"]; - - // Advertise the presence or absence of the globops snomask in CAPAB CAPABILITIES. Services - // needs to know about it and since m_globops is not marked as VF_(OPT)COMMON in v3 we - // advertise it here to not break linking to previous versions. - capabilities["GLOBOPS"] = ConvToStr(!!ServerInstance->Modules.Find("globops")); - - } - else - { - std::string extbans; - if (BuildExtBanList(extbans)) - WriteLine("CAPAB EXTBANS :" + extbans); - } - - // If SHA256 hashing support is available then send a challenge token. - if (ServerInstance->Modules.FindService(SERVICE_DATA, "hash/sha256")) - { - SetOurChallenge(ServerInstance->GenRandomStr(20)); - capabilities["CHALLENGE"] = GetOurChallenge(); - } - - std::stringstream capabilitystr; - char separator = ':'; - for (const auto& [capkey, capvalue] : capabilities) - { - capabilitystr << separator << capkey << '=' << capvalue; - separator = ' '; - } - - this->WriteLine("CAPAB CAPABILITIES " + capabilitystr.str()); - this->WriteLine("CAPAB END"); -} - -/* Isolate and return the elements that are different between two comma separated lists */ -void TreeSocket::ListDifference(const std::string& one, const std::string& two, char sep, - std::string& mleft, std::string& mright) -{ - std::set values; - irc::sepstream sepleft(one, sep); - irc::sepstream sepright(two, sep); - std::string item; - while (sepleft.GetToken(item)) - { - values.insert(item); - } - while (sepright.GetToken(item)) - { - if (!values.erase(item)) - { - mright.push_back(sep); - mright.append(item); - } - } - for (const auto& value : values) - { - mleft.push_back(sep); - mleft.append(value); - } -} - -bool TreeSocket::Capab(const CommandBase::Params& params) -{ - if (params.empty()) - { - this->SendError("Invalid number of parameters for CAPAB - Mismatched version"); - return false; - } - if (irc::equals(params[0], "START")) - { - capab->requiredmodules.reset(); - capab->optionalmodules.reset(); - capab->CapKeys.clear(); - - if (params.size() > 1) - proto_version = ConvToNum(params[1]); - - if (proto_version < PROTO_OLDEST) - { - SendError("CAPAB negotiation failed: Server is using protocol version " - + (proto_version ? ConvToStr(proto_version) : "1201 or older") - + " which is too old to link with this server (protocol versions " - + ConvToStr(PROTO_OLDEST) + " to " + ConvToStr(PROTO_NEWEST) + " are supported)"); - return false; - } - - SendCapabilities(2); - } - else if (irc::equals(params[0], "END")) - { - std::ostringstream errormsg; - if (!CompareModules(VF_COMMON, proto_version, this->capab->requiredmodules, errormsg)) - { - SendError("CAPAB negotiation failed. Required modules incorrectly matched on these servers." - + errormsg.str()); - return false; - } - else if (!CompareModules(VF_OPTCOMMON, proto_version, this->capab->optionalmodules, errormsg)) - { - if (Utils->AllowOptCommon) - { - ServerInstance->SNO.WriteToSnoMask('l', "Optional modules do not match. Some features may not work globally!" - + errormsg.str()); - } - else - { - SendError("CAPAB negotiation failed. Optional modules incorrectly matched on these servers and is not enabled." - + errormsg.str()); - return false; - } - } - - if (!capab->ChanModes.empty()) - { - if (capab->ChanModes != BuildModeList(MODETYPE_CHANNEL)) - { - std::string diffIneed; - std::string diffUneed; - ListDifference(capab->ChanModes, BuildModeList(MODETYPE_CHANNEL), ' ', diffIneed, diffUneed); - if (diffIneed.length() || diffUneed.length()) - { - std::string reason = "Channel modes not matched on these servers."; - if (diffIneed.length()) - reason += " Not loaded here:" + diffIneed; - if (diffUneed.length()) - reason += " Not loaded there:" + diffUneed; - this->SendError("CAPAB negotiation failed: " + reason); - } - } - } - - if (!capab->UserModes.empty()) - { - if (capab->UserModes != BuildModeList(MODETYPE_USER)) - { - std::string diffIneed; - std::string diffUneed; - ListDifference(capab->UserModes, BuildModeList(MODETYPE_USER), ' ', diffIneed, diffUneed); - if (diffIneed.length() || diffUneed.length()) - { - std::string reason = "User modes not matched on these servers."; - if (diffIneed.length()) - reason += " Not loaded here:" + diffIneed; - if (diffUneed.length()) - reason += " Not loaded there:" + diffUneed; - this->SendError("CAPAB negotiation failed: " + reason); - } - } - } - - if (!capab->ExtBans.empty()) - { - std::string myextbans; - if (BuildExtBanList(myextbans)) - { - std::string missing_here; - std::string missing_there; - ListDifference(capab->ExtBans, myextbans, ' ', missing_here, missing_there); - if (!missing_here.empty() || !missing_there.empty()) - { - if (Utils->AllowOptCommon) - { - ServerInstance->SNO.WriteToSnoMask('l', - "ExtBan lists do not match, some bans/exemptions may not work globally.{}{}{}{}", - missing_here.length() ? " Not loaded here:" : "", missing_here, - missing_there.length() ? " Not loaded there:" : "", missing_there); - } - else - { - std::string reason = "ExtBans not matched on these servers."; - if (missing_here.length()) - reason += " Not loaded here:" + missing_here; - if (missing_there.length()) - reason += " Not loaded there:" + missing_there; - this->SendError("CAPAB negotiation failed: " + reason); - return false; - } - } - } - } - - if (this->capab->CapKeys.find("CASEMAPPING") != this->capab->CapKeys.end()) - { - const std::string casemapping = this->capab->CapKeys.find("CASEMAPPING")->second; - if (casemapping != ServerInstance->Config->CaseMapping) - { - std::string reason = "The casemapping of the remote server differs to that of the local server." - " Local casemapping: " + ServerInstance->Config->CaseMapping + - " Remote casemapping: " + casemapping; - this->SendError("CAPAB negotiation failed: " + reason); - return false; - } - } - - /* Challenge response, store their challenge for our password */ - std::map::iterator n = this->capab->CapKeys.find("CHALLENGE"); - if ((n != this->capab->CapKeys.end()) && (ServerInstance->Modules.FindService(SERVICE_DATA, "hash/sha256"))) - { - /* Challenge-response is on now */ - this->SetTheirChallenge(n->second); - if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) - { - this->SendCapabilities(2); - this->WriteLine(fmt::format("SERVER {} {} {}{} :{}", - ServerInstance->Config->ServerName, - TreeSocket::MakePass(capab->link->SendPass, capab->theirchallenge), - proto_version == PROTO_INSPIRCD_3 ? "0 " : "", - ServerInstance->Config->ServerId, - ServerInstance->Config->ServerDesc - )); - } - } - else - { - // They didn't specify a challenge or we don't have sha256, we use plaintext - if (this->LinkState == CONNECTING) - { - this->SendCapabilities(2); - this->WriteLine(fmt::format("SERVER {} {} {}{} :{}", - ServerInstance->Config->ServerName, - capab->link->SendPass, - proto_version == PROTO_INSPIRCD_3 ? "0 " : "", - ServerInstance->Config->ServerId, - ServerInstance->Config->ServerDesc - )); - } - } - } - else if (irc::equals(params[0] , "MODULES")) - { - if (params.size() >= 2) - ParseModules(params[1], capab->requiredmodules); - } - else if (irc::equals(params[0], "MODSUPPORT")) - { - if (params.size() >= 2) - ParseModules(params[1], capab->optionalmodules); - } - else if (irc::equals(params[0], "CHANMODES") && (params.size() == 2)) - { - capab->ChanModes = params[1]; - } - else if (irc::equals(params[0], "USERMODES") && (params.size() == 2)) - { - capab->UserModes = params[1]; - } - else if (irc::equals(params[0], "EXTBANS") && (params.size() == 2)) - { - capab->ExtBans = params[1]; - } - else if (irc::equals(params[0], "CAPABILITIES") && (params.size() == 2)) - { - irc::spacesepstream capabs(params[1]); - std::string item; - while (capabs.GetToken(item)) - { - /* Process each key/value pair */ - std::string::size_type equals = item.find('='); - if (equals != std::string::npos) - { - std::string var(item, 0, equals); - std::string value(item, equals+1); - capab->CapKeys[var] = value; - } - } - } - return true; -} -- cgit v1.3.1-10-gc9f91