summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadie Powell <sadie@witchery.services>2023-11-14 15:02:04 +0000
committerSadie Powell <sadie@witchery.services>2023-11-14 15:02:04 +0000
commitb28180d680f974b7d3cf72667681b8cda6a39b0a (patch)
tree45ce01374a4eb95c7b9bca73f25bc28dfefb2721
parent0f1f0c5a221d199fefc38e116a98fb4ff2c0a4f3 (diff)
Implement support for the ANONYMOUS SASL mechanism.
-rw-r--r--include/protocol.h2
-rw-r--r--modules/m_sasl.cpp44
-rw-r--r--modules/protocol/inspircd.cpp32
-rw-r--r--modules/protocol/solanum.cpp10
-rw-r--r--modules/protocol/unrealircd.cpp14
-rw-r--r--src/protocol.cpp2
6 files changed, 80 insertions, 24 deletions
diff --git a/include/protocol.h b/include/protocol.h
index 4f7990b51..9967012c0 100644
--- a/include/protocol.h
+++ b/include/protocol.h
@@ -64,6 +64,8 @@ class CoreExport IRCDProto : public Service
bool CanCertFP;
/* Can we send arbitrary message tags? */
bool CanSendTags;
+ /* Can users log out before being fully connected? */
+ bool CanSVSLogout;
/* Whether this IRCd requires unique IDs for each user or server. See TS6/P10. */
bool RequiresID;
/* If this IRCd has unique ids, whether the IDs and nicknames are ambiguous */
diff --git a/modules/m_sasl.cpp b/modules/m_sasl.cpp
index d14118e3c..c7e3a0585 100644
--- a/modules/m_sasl.cpp
+++ b/modules/m_sasl.cpp
@@ -124,6 +124,42 @@ class External : public Mechanism
}
};
+class Anonymous : public Mechanism
+{
+ public:
+ Anonymous(Module *o) : Mechanism(o, "ANONYMOUS") { }
+
+ void ProcessMessage(Session *sess, const SASL::Message &m) override
+ {
+ if (!IRCD->CanSVSLogout && !User::Find(sess->uid))
+ {
+ // This IRCd can't log users out yet.
+ sasl->Fail(sess);
+ delete sess;
+ return;
+ }
+
+ if (m.type == "S")
+ {
+ sasl->SendMessage(sess, "C", "+");
+ }
+ else if (m.type == "C")
+ {
+ Anope::string decoded;
+ Anope::B64Decode(m.data, decoded);
+
+ Anope::string user = "A user";
+ if (!sess->hostname.empty() && !sess->ip.empty())
+ user = sess->hostname + " (" + sess->ip + ")";
+ if (!decoded.empty())
+ user += " [" + decoded + "]";
+
+ Log(this->owner, "sasl", Config->GetClient("NickServ")) << user << " unidentified using SASL ANONYMOUS";
+ sasl->Succeed(sess, nullptr);
+ }
+ }
+};
+
class SASLService : public SASL::Service, public Timer
{
std::map<Anope::string, SASL::Session *> sessions;
@@ -257,7 +293,10 @@ class SASLService : public SASL::Service, public Timer
NickAlias *na = NickAlias::Find(nc->display);
if (user)
{
- user->Identify(na);
+ if (na)
+ user->Identify(na);
+ else
+ user->Logout();
}
else
{
@@ -302,6 +341,7 @@ class ModuleSASL : public Module
{
SASLService sasl;
+ Anonymous anonymous;
Plain plain;
External *external = nullptr;
@@ -322,7 +362,7 @@ class ModuleSASL : public Module
public:
ModuleSASL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
- sasl(this), plain(this)
+ sasl(this), anonymous(this), plain(this)
{
try
{
diff --git a/modules/protocol/inspircd.cpp b/modules/protocol/inspircd.cpp
index e76d745e3..3183e59ee 100644
--- a/modules/protocol/inspircd.cpp
+++ b/modules/protocol/inspircd.cpp
@@ -75,6 +75,7 @@ class InspIRCdProto : public IRCDProto
CanSQLineChannel = true;
CanSZLine = true;
CanSVSHold = true;
+ CanSVSLogout = true;
CanCertFP = true;
CanSendTags = true;
RequiresID = true;
@@ -461,27 +462,30 @@ class InspIRCdProto : public IRCDProto
{
SendAccount(uid, na);
- if (!na->GetVhostIdent().empty())
- UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGIDENT " << uid << " " << na->GetVhostIdent();
- if (!na->GetVhostHost().empty())
- UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGHOST " << uid << " " << na->GetVhostHost();
-
- SASLUser su;
- su.uid = uid;
- su.acc = na->nc->display;
- su.created = Anope::CurTime;
-
- for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
+ // Expire old pending sessions or other sessions for this user.
+ for (auto it = saslusers.begin(); it != saslusers.end(); )
{
- SASLUser &u = *it;
-
+ const SASLUser &u = *it;
if (u.created + 30 < Anope::CurTime || u.uid == uid)
it = saslusers.erase(it);
else
++it;
}
- saslusers.push_back(su);
+ if (na)
+ {
+ if (!na->GetVhostIdent().empty())
+ UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGIDENT " << uid << " " << na->GetVhostIdent();
+ if (!na->GetVhostHost().empty())
+ UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGHOST " << uid << " " << na->GetVhostHost();
+
+ // Mark this SASL session as pending user introduction.
+ SASLUser su;
+ su.uid = uid;
+ su.acc = na->nc->display;
+ su.created = Anope::CurTime;
+ saslusers.push_back(su);
+ }
}
bool IsExtbanValid(const Anope::string &mask) override
diff --git a/modules/protocol/solanum.cpp b/modules/protocol/solanum.cpp
index 1ba740d04..c01c4f551 100644
--- a/modules/protocol/solanum.cpp
+++ b/modules/protocol/solanum.cpp
@@ -43,6 +43,7 @@ class SolanumProto : public IRCDProto
CanSZLine = true;
CanSVSNick = true;
CanSVSHold = true;
+ CanSVSLogout = true;
CanSetVHost = true;
RequiresID = true;
MaxModes = 4;
@@ -158,8 +159,13 @@ class SolanumProto : public IRCDProto
void SendSVSLogin(const Anope::string &uid, NickAlias *na) override
{
Server *s = Server::Find(uid.substr(0, 3));
- UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * " << (!na->GetVhostIdent().empty() ? na->GetVhostIdent() : '*')
- << " " << (!na->GetVhostHost().empty() ? na->GetVhostHost() : '*') << " " << na->nc->display;
+
+ UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * "
+ << (na && !na->GetVhostIdent().empty() ? na->GetVhostIdent() : '*')
+ << " "
+ << (na && !na->GetVhostHost().empty() ? na->GetVhostHost() : '*')
+ << " "
+ << (na ? na->nc->display : "0");
}
};
diff --git a/modules/protocol/unrealircd.cpp b/modules/protocol/unrealircd.cpp
index a6b0aaef8..88826b7da 100644
--- a/modules/protocol/unrealircd.cpp
+++ b/modules/protocol/unrealircd.cpp
@@ -34,6 +34,7 @@ class UnrealIRCdProto : public IRCDProto
CanSQLineChannel = true;
CanSZLine = true;
CanSVSHold = true;
+ CanSVSLogout = true;
CanCertFP = true;
RequiresID = true;
MaxModes = 12;
@@ -401,11 +402,14 @@ class UnrealIRCdProto : public IRCDProto
distmask = uid.substr(0, p);
}
- if (!na->GetVhostIdent().empty())
- UplinkSocket::Message(Me) << "CHGIDENT " << uid << " " << na->GetVhostIdent();
- if (!na->GetVhostHost().empty())
- UplinkSocket::Message(Me) << "CHGHOST " << uid << " " << na->GetVhostHost();
- UplinkSocket::Message(Me) << "SVSLOGIN " << distmask << " " << uid << " " << na->nc->display;
+ if (na)
+ {
+ if (!na->GetVhostIdent().empty())
+ UplinkSocket::Message(Me) << "CHGIDENT " << uid << " " << na->GetVhostIdent();
+ if (!na->GetVhostHost().empty())
+ UplinkSocket::Message(Me) << "CHGHOST " << uid << " " << na->GetVhostHost();
+ }
+ UplinkSocket::Message(Me) << "SVSLOGIN " << distmask << " " << uid << " " << (na ? na->nc->display : "0");
}
bool IsIdentValid(const Anope::string &ident) override
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 090187819..98953cabc 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -25,7 +25,7 @@ IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator,
{
DefaultPseudoclientModes = "+io";
CanSVSNick = CanSVSJoin = CanSetVHost = CanSetVIdent = CanSNLine = CanSQLine = CanSQLineChannel
- = CanSZLine = CanSVSHold = CanCertFP = CanSendTags = RequiresID = AmbiguousID = false;
+ = CanSZLine = CanSVSHold = CanCertFP = CanSendTags = CanSVSLogout = RequiresID = AmbiguousID = false;
MaxModes = 3;
MaxLine = 512;