From 69a0f3bec2cfed1436385a41fe73b2a95f5bf64a Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 12 Oct 2023 19:09:44 +0100 Subject: [PATCH 1/6] Fix removing entries by an alias in chanserv/access and chanserv/xop. --- modules/commands/cs_access.cpp | 7 ++++++- modules/commands/cs_xop.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/commands/cs_access.cpp b/modules/commands/cs_access.cpp index 1a6c93514..cab343057 100644 --- a/modules/commands/cs_access.cpp +++ b/modules/commands/cs_access.cpp @@ -229,7 +229,12 @@ class CommandCSAccess : public Command { Anope::string mask = params[2]; - if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos && !NickAlias::Find(mask)) + const NickAlias *na = NickAlias::Find(mask); + if (na && na->nc) + { + mask = na->nc->display; + } + else if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos) { User *targ = User::Find(mask, true); if (targ != NULL) diff --git a/modules/commands/cs_xop.cpp b/modules/commands/cs_xop.cpp index 33b2f564e..e2a1994e8 100644 --- a/modules/commands/cs_xop.cpp +++ b/modules/commands/cs_xop.cpp @@ -246,7 +246,12 @@ class CommandCSXOP : public Command const ChanAccess *highest = access.Highest(); bool override = false; - if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos && !NickAlias::Find(mask)) + const NickAlias *na = NickAlias::Find(mask); + if (na && na->nc) + { + mask = na->nc->display; + } + else if (!isdigit(mask[0]) && mask.find_first_of("#!*@") == Anope::string::npos) { User *targ = User::Find(mask, true); if (targ != NULL) From 02940e4ea810f2fa634f5a783f5ed966b936d6f4 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 20 Oct 2023 18:08:49 +0100 Subject: [PATCH 2/6] Fix a misleading temporary variable in ns_register. --- modules/commands/ns_register.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index bd188637c..d38b07bc6 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -25,13 +25,12 @@ class CommandNSConfirm : public Command void Execute(CommandSource &source, const std::vector ¶ms) anope_override { - const Anope::string &passcode = params[0]; - if (source.nc && (!source.nc->HasExt("UNCONFIRMED") || source.IsOper()) && source.HasPriv("nickserv/confirm")) { - NickAlias *na = NickAlias::Find(passcode); + const Anope::string &nick = params[0]; + NickAlias *na = NickAlias::Find(nick); if (na == NULL) - source.Reply(NICK_X_NOT_REGISTERED, passcode.c_str()); + source.Reply(NICK_X_NOT_REGISTERED, nick.c_str()); else if (na->nc->HasExt("UNCONFIRMED") == false) source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str()); else @@ -58,6 +57,7 @@ class CommandNSConfirm : public Command } else if (source.nc) { + const Anope::string &passcode = params[0]; Anope::string *code = source.nc->GetExt("passcode"); if (code != NULL && *code == passcode) { From 97fa6d84bcb70b3b87d3fd7cc14f3b2567ca4e11 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 20 Oct 2023 18:32:57 +0100 Subject: [PATCH 3/6] Fix confirming an unconfirmed operator's account. --- modules/commands/ns_register.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index d38b07bc6..db606cb5b 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -25,7 +25,10 @@ class CommandNSConfirm : public Command void Execute(CommandSource &source, const std::vector ¶ms) anope_override { - if (source.nc && (!source.nc->HasExt("UNCONFIRMED") || source.IsOper()) && source.HasPriv("nickserv/confirm")) + Anope::string *code = source.nc ? source.nc->GetExt("passcode") : NULL; + bool confirming_other = !code || *code != params[0]; + + if (source.nc && (!source.nc->HasExt("UNCONFIRMED") || (source.IsOper() && confirming_other)) && source.HasPriv("nickserv/confirm")) { const Anope::string &nick = params[0]; NickAlias *na = NickAlias::Find(nick); @@ -58,7 +61,6 @@ class CommandNSConfirm : public Command else if (source.nc) { const Anope::string &passcode = params[0]; - Anope::string *code = source.nc->GetExt("passcode"); if (code != NULL && *code == passcode) { NickCore *nc = source.nc; From eb409fc6eb4dfbf82b6dca5a55577c8d6f4882c5 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 24 Oct 2023 18:00:34 +0100 Subject: [PATCH 4/6] When changing the nick of a user on inspircd3 send the expected ts. This should prevent users being renicked if they changed their nick between services sending the renick and the IRCd receiving it. --- modules/protocol/inspircd3.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/protocol/inspircd3.cpp b/modules/protocol/inspircd3.cpp index ad29b56d9..40da697e7 100644 --- a/modules/protocol/inspircd3.cpp +++ b/modules/protocol/inspircd3.cpp @@ -112,6 +112,11 @@ class InspIRCd3Proto : public IRCDProto user->KillInternal(source, buf); } + void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) + { + UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when << " " << u->timestamp; + } + void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override { UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg; From 1eba69d0352b8396de19ab0b19f3aa7d2eb2ef87 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 24 Oct 2023 18:10:32 +0100 Subject: [PATCH 5/6] Fix a missing override keyword. --- modules/protocol/inspircd3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/protocol/inspircd3.cpp b/modules/protocol/inspircd3.cpp index 40da697e7..79db757ea 100644 --- a/modules/protocol/inspircd3.cpp +++ b/modules/protocol/inspircd3.cpp @@ -112,7 +112,7 @@ class InspIRCd3Proto : public IRCDProto user->KillInternal(source, buf); } - void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) + void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) anope_override { UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when << " " << u->timestamp; } From ba163027bd9d62d3ae22bc1f8eb8cbe8bc478bf7 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 16 Nov 2023 18:14:15 +0000 Subject: [PATCH 6/6] Make the SASL PLAIN implementation more robust. - Reject auth attempts that try to authenticate using an alternate authorization identity. - Reject auth attempts that contain extraneous null bytes in the string as required by the SASL PLAIN RFC. - General code quality cleanup. --- modules/m_sasl.cpp | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/modules/m_sasl.cpp b/modules/m_sasl.cpp index 0475b94e5..70ea2feaf 100644 --- a/modules/m_sasl.cpp +++ b/modules/m_sasl.cpp @@ -25,37 +25,47 @@ class Plain : public Mechanism } else if (m.type == "C") { - Anope::string decoded; - Anope::B64Decode(m.data, decoded); + // message = [authzid] UTF8NUL authcid UTF8NUL passwd + Anope::string message; + Anope::B64Decode(m.data, message); - size_t p = decoded.find('\0'); - if (p == Anope::string::npos) - { - sasl->Fail(sess); - delete sess; - return; - } - decoded = decoded.substr(p + 1); - - p = decoded.find('\0'); - if (p == Anope::string::npos) + size_t zcsep = message.find('\0'); + if (zcsep == Anope::string::npos) { sasl->Fail(sess); delete sess; return; } - Anope::string acc = decoded.substr(0, p), - pass = decoded.substr(p + 1); - - if (acc.empty() || pass.empty() || !IRCD->IsNickValid(acc) || pass.find_first_of("\r\n") != Anope::string::npos) + size_t cpsep = message.find('\0', zcsep + 1); + if (cpsep == Anope::string::npos) { sasl->Fail(sess); delete sess; return; } - SASL::IdentifyRequest *req = new SASL::IdentifyRequest(this->owner, m.source, acc, pass, sess->hostname, sess->ip); + Anope::string authzid = message.substr(0, zcsep); + Anope::string authcid = message.substr(zcsep + 1, cpsep - zcsep - 1); + + // We don't support having an authcid that is different to the authzid. + if (!authzid.empty() && authzid != authcid) + { + sasl->Fail(sess); + delete sess; + return; + } + + Anope::string passwd = message.substr(cpsep + 1); + + if (authcid.empty() || passwd.empty() || !IRCD->IsNickValid(authcid) || passwd.find_first_of("\r\n\0") != Anope::string::npos) + { + sasl->Fail(sess); + delete sess; + return; + } + + SASL::IdentifyRequest *req = new SASL::IdentifyRequest(this->owner, m.source, authcid, passwd, sess->hostname, sess->ip); FOREACH_MOD(OnCheckAuthentication, (NULL, req)); req->Dispatch(); }