diff options
| author | 2026-06-24 03:40:44 +0100 | |
|---|---|---|
| committer | 2026-06-24 21:21:59 +0100 | |
| commit | 7ec34045f5ffbd548ddb72a712a0b175b953ffee (patch) | |
| tree | 2961563a88f0a7cf2fa1139fcb8e5bcbb46eb2fe /modules | |
| parent | Merge branch 'insp4' into master. (diff) | |
Move the challenge out of CAPAB CAPABILITIES into its own command.
Diffstat (limited to 'modules')
| -rw-r--r-- | modules/spanningtree/capab.cpp | 80 | ||||
| -rw-r--r-- | modules/spanningtree/hmac.cpp | 8 | ||||
| -rw-r--r-- | modules/spanningtree/server.cpp | 2 | ||||
| -rw-r--r-- | modules/spanningtree/treesocket.h | 2 | ||||
| -rw-r--r-- | modules/spanningtree/utils.cpp | 4 |
5 files changed, 61 insertions, 35 deletions
diff --git a/modules/spanningtree/capab.cpp b/modules/spanningtree/capab.cpp index 49c046074..fc124d0a8 100644 --- a/modules/spanningtree/capab.cpp +++ b/modules/spanningtree/capab.cpp @@ -197,7 +197,7 @@ namespace }; // If SHA256 hashing support is available then send a challenge token. - if (ServerInstance->Modules.FindService("Hash::Provider", "sha256")) + if (ts->proto_version < PROTO_INSPIRCD_5 && ServerInstance->Modules.FindService("Hash::Provider", "sha256")) { ts->SetOurChallenge(ServerInstance->GenRandomStr(20)); capabilities["CHALLENGE"] = ts->GetOurChallenge(); @@ -248,6 +248,21 @@ namespace return modules.str(); } + // Parses a challenge in the format "<algo> [<algo>]+ :<challenge>". + void ParseChallenge(const CommandBase::Params& params, std::string& out) + { + for (const auto& algorithm : insp::iterator_range(params.begin() + 1, params.end() - 1)) + { + // For now we only support HMAC-SHA-256 here. + if (insp::casemapped_equals(algorithm, "hmac-sha256")) + { + out = Percent::Decode(params.back()); + ServerInstance->Logs.Debug(MODNAME, "Parsed challenge: {:?}", out); + break; + } + } + } + // 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<CapabData::ModuleMap>& out) { @@ -340,6 +355,20 @@ void TreeSocket::SendCapabilities(int phase) if (phase < 2) return; + + std::vector<std::string> algorithms; + if (proto_version >= PROTO_INSPIRCD_5) + { + std::vector<char> challenge(32); + ServerInstance->GenRandom(challenge.data(), challenge.size()); + SetOurChallenge(std::string(challenge.begin(), challenge.end())); + + MessageBuilder("CAPAB", true) + .Push("CHALLENGE") + .Push("hmac-sha256", Percent::Encode(GetOurChallenge())) + .Unicast(this); + } + MessageBuilder("CAPAB", true) .Push("CAPABILITIES", FormatCapabilities(this)) .Unicast(this); @@ -529,36 +558,15 @@ bool TreeSocket::Capab(const CommandBase::Params& params) } } - /* Challenge response, store their challenge for our password */ - std::map<std::string, std::string>::iterator n = this->capab->CapKeys.find("CHALLENGE"); - if ((n != this->capab->CapKeys.end()) && (ServerInstance->Modules.FindService("Hash::Provider", "sha256"))) + if (this->LinkState == CONNECTING) { - /* Challenge-response is on now */ - this->SetTheirChallenge(n->second); - if (!this->GetTheirChallenge().empty() && (this->LinkState == CONNECTING)) - { - this->SendCapabilities(2); - MessageBuilder("SERVER", true) - .Push(ServerInstance->Config->ServerName, - TreeSocket::MakePass(capab->link->SendPass, capab->theirchallenge), - ServerInstance->Config->ServerId, - ServerInstance->Config->ServerDesc) - .Unicast(this); - } - } - else - { - // They didn't specify a challenge or we don't have sha256, we use plaintext - if (this->LinkState == CONNECTING) - { - this->SendCapabilities(2); - MessageBuilder("SERVER", true) - .Push(ServerInstance->Config->ServerName, - capab->link->SendPass, - ServerInstance->Config->ServerId, - ServerInstance->Config->ServerDesc) - .Unicast(this); - } + this->SendCapabilities(2); + MessageBuilder("SERVER", true) + .Push(ServerInstance->Config->ServerName, + MakePass(capab->link->SendPass, capab->theirchallenge), + ServerInstance->Config->ServerId, + ServerInstance->Config->ServerDesc) + .Unicast(this); } } else if (insp::casemapped_equals(params[0] , "MODULES")) @@ -571,6 +579,11 @@ bool TreeSocket::Capab(const CommandBase::Params& params) if (params.size() >= 2) ParseModules(params[1], capab->optionalmodules); } + else if (insp::casemapped_equals(params[0], "CHALLENGE")) + { + if (params.size() >= 3) + ParseChallenge(params, capab->theirchallenge); + } else if (insp::casemapped_equals(params[0], "CHANMODES") && (params.size() == 2)) { capab->ChanModes = params[1]; @@ -595,6 +608,13 @@ bool TreeSocket::Capab(const CommandBase::Params& params) { std::string var(item, 0, equals); std::string value(item, equals+1); + + if (proto_version < PROTO_INSPIRCD_5 && insp::casemapped_equals(var, "CHALLENGE")) + { + this->SetTheirChallenge(value); + continue; + } + capab->CapKeys[var] = value; } } diff --git a/modules/spanningtree/hmac.cpp b/modules/spanningtree/hmac.cpp index 17d22e96f..2b4a2eef2 100644 --- a/modules/spanningtree/hmac.cpp +++ b/modules/spanningtree/hmac.cpp @@ -59,7 +59,13 @@ std::string TreeSocket::MakePass(const std::string& password, const std::string& */ auto* sha256 = ServerInstance->Modules.FindDataService<Hash::Provider>("Hash::Provider", "sha256"); if (sha256 && !challenge.empty()) - return "AUTH:" + Base64::Encode(Hash::HMAC(sha256, password, challenge)); + { + const auto hmac = Hash::HMAC(sha256, password, challenge); + if (proto_version >= PROTO_INSPIRCD_5) + return FMT::format("$hmac-sha256:{}", Percent::Encode(hmac)); + else + return FMT::format("AUTH:{}", Base64::Encode(hmac)); + } if (!challenge.empty() && !sha256) ServerInstance->Logs.Warning(MODNAME, "Not authenticating to server using HMAC-SHA256 because we don't have an SHA256 provider (e.g. the sha2 module) loaded!"); diff --git a/modules/spanningtree/server.cpp b/modules/spanningtree/server.cpp index e1d7b7469..75524024e 100644 --- a/modules/spanningtree/server.cpp +++ b/modules/spanningtree/server.cpp @@ -241,7 +241,7 @@ bool TreeSocket::Inbound_Server(CommandBase::Params& params) // along with the sendpass from this block. MessageBuilder("SERVER", true) .Push(ServerInstance->Config->ServerName, - TreeSocket::MakePass(x->SendPass, this->GetTheirChallenge()), + MakePass(x->SendPass, this->GetTheirChallenge()), ServerInstance->Config->ServerId, ServerInstance->Config->ServerDesc) .Unicast(this); diff --git a/modules/spanningtree/treesocket.h b/modules/spanningtree/treesocket.h index 14a01f1d4..be2996904 100644 --- a/modules/spanningtree/treesocket.h +++ b/modules/spanningtree/treesocket.h @@ -243,7 +243,7 @@ public: /** Construct a password, optionally hashed with the other side's * challenge string */ - static std::string MakePass(const std::string& password, const std::string& challenge); + std::string MakePass(const std::string& password, const std::string& challenge); /** When an outbound connection finishes connecting, we receive * this event, and must send our SERVER string to the other diff --git a/modules/spanningtree/utils.cpp b/modules/spanningtree/utils.cpp index 4a508f544..c6af1ec2c 100644 --- a/modules/spanningtree/utils.cpp +++ b/modules/spanningtree/utils.cpp @@ -302,8 +302,8 @@ void SpanningTreeUtilities::ReadConfiguration(ConfigStatus& status) if ((L->SendPass.find(' ') != std::string::npos) || (L->RecvPass.find(' ') != std::string::npos)) throw ModuleException(Creator->weak_from_this(), "Link block '" + L->Name + "' has a password set that contains a space character which is invalid"); - if ((L->SendPass[0] == ':') || (L->RecvPass[0] == ':')) - throw ModuleException(Creator->weak_from_this(), "Link block '" + L->Name + "' has a password set that begins with a colon (:) which is invalid"); + if ((L->SendPass[0] == ':') || (L->RecvPass[0] == ':') || (L->SendPass[0] == '$') || (L->RecvPass[0] == '$')) + throw ModuleException(Creator->weak_from_this(), "Link block '" + L->Name + "' has a password set that begins with a colon (:) or dollar sign ($) which is invalid"); if (L->IPAddr.empty()) { |
