aboutsummaryrefslogtreecommitdiffstats
path: root/modules/spanningtree
diff options
context:
space:
mode:
authorGravatar Sadie Powell2026-06-24 03:40:44 +0100
committerGravatar Sadie Powell2026-06-24 21:21:59 +0100
commit7ec34045f5ffbd548ddb72a712a0b175b953ffee (patch)
tree2961563a88f0a7cf2fa1139fcb8e5bcbb46eb2fe /modules/spanningtree
parentMerge branch 'insp4' into master. (diff)
Move the challenge out of CAPAB CAPABILITIES into its own command.
Diffstat (limited to 'modules/spanningtree')
-rw-r--r--modules/spanningtree/capab.cpp80
-rw-r--r--modules/spanningtree/hmac.cpp8
-rw-r--r--modules/spanningtree/server.cpp2
-rw-r--r--modules/spanningtree/treesocket.h2
-rw-r--r--modules/spanningtree/utils.cpp4
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())
{