diff options
-rw-r--r-- | data/example.conf | 7 | ||||
-rw-r--r-- | data/modules.example.conf | 10 | ||||
-rw-r--r-- | include/defs.h | 1 | ||||
-rw-r--r-- | include/modules/sasl.h | 63 | ||||
-rw-r--r-- | include/protocol.h | 3 | ||||
-rw-r--r-- | modules/m_sasl.cpp | 284 | ||||
-rw-r--r-- | modules/protocol/charybdis.cpp | 104 | ||||
-rw-r--r-- | modules/protocol/inspircd12.cpp | 124 | ||||
-rw-r--r-- | modules/protocol/inspircd20.cpp | 2 | ||||
-rw-r--r-- | modules/protocol/unreal.cpp | 100 |
10 files changed, 448 insertions, 250 deletions
diff --git a/data/example.conf b/data/example.conf index 4762ad084..fbb7e310e 100644 --- a/data/example.conf +++ b/data/example.conf @@ -276,13 +276,6 @@ module * If the protocol module you have loaded does not support this, this setting will have no effect. */ use_server_side_topiclock = yes - - /* - * Some IRCds allow "SASL" authentication to let users identify to Services - * during the IRCd user registration process. If set, Services will allow - * authenticating users through this mechanism. - */ - sasl = yes } /* diff --git a/data/modules.example.conf b/data/modules.example.conf index 8e41aa734..57430e2a7 100644 --- a/data/modules.example.conf +++ b/data/modules.example.conf @@ -424,6 +424,16 @@ module { name = "help" } } /* + * m_sasl + * + * Some IRCds allow "SASL" authentication to let users identify to Services + * during the IRCd user registration process. If this module is loaded, Services will allow + * authenticating users through this mechanism. Currently supported mechanisms are: + * PLAIN, EXTERNAL. + */ +module { name = "m_sasl" } + +/* * m_sql_authentication [EXTRA] * * This module allows authenticating users against an external SQL database using a custom diff --git a/include/defs.h b/include/defs.h index 1d61c6c92..3d8ebf4ff 100644 --- a/include/defs.h +++ b/include/defs.h @@ -52,4 +52,5 @@ struct Exception; struct MemoInfo; struct ModeLock; struct Oper; +namespace SASL { struct Message; } diff --git a/include/modules/sasl.h b/include/modules/sasl.h new file mode 100644 index 000000000..836c26d19 --- /dev/null +++ b/include/modules/sasl.h @@ -0,0 +1,63 @@ +/* + * + * (C) 2014 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + */ + +namespace SASL +{ + struct Message + { + Anope::string source; + Anope::string target; + Anope::string type; + Anope::string data; + Anope::string ext; + }; + + class Mechanism; + + struct Session + { + time_t created; + Anope::string uid; + Reference<Mechanism> mech; + + Session(Mechanism *m, const Anope::string &u) : created(Anope::CurTime), uid(u), mech(m) { } + virtual ~Session() { } + }; + + /* PLAIN, EXTERNAL, etc */ + class Mechanism : public Service + { + public: + Mechanism(Module *o, const Anope::string &sname) : Service(o, "SASL::Mechanism", sname) { } + + virtual Session* CreateSession(const Anope::string &uid) { return new Session(this, uid); } + + virtual void ProcessMessage(Session *session, const Message &) = 0; + }; + + class Service : public ::Service + { + public: + Service(Module *o) : ::Service(o, "SASL::Service", "sasl") { } + + virtual void ProcessMessage(const Message &) = 0; + + virtual Anope::string GetAgent() = 0; + + virtual Session* GetSession(const Anope::string &uid) = 0; + + virtual void SendMessage(SASL::Session *session, const Anope::string &type, const Anope::string &data) = 0; + + virtual void Succeed(Session *, NickCore *) = 0; + virtual void Fail(Session *) = 0; + virtual void SendMechs(Session *) = 0; + }; +} + +static ServiceReference<SASL::Service> sasl("SASL::Service", "sasl"); + diff --git a/include/protocol.h b/include/protocol.h index 9eee494ea..0f8482b4e 100644 --- a/include/protocol.h +++ b/include/protocol.h @@ -217,6 +217,9 @@ class CoreExport IRCDProto : public Service */ virtual void SendOper(User *u); + virtual void SendSASLMessage(const SASL::Message &) { } + virtual void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) { } + virtual bool IsNickValid(const Anope::string &); virtual bool IsChannelValid(const Anope::string &); virtual bool IsIdentValid(const Anope::string &); diff --git a/modules/m_sasl.cpp b/modules/m_sasl.cpp new file mode 100644 index 000000000..bdc0ef1a2 --- /dev/null +++ b/modules/m_sasl.cpp @@ -0,0 +1,284 @@ +/* + * + * (C) 2014 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + */ + +#include "module.h" +#include "modules/sasl.h" +#include "modules/ns_cert.h" + +class Plain : public SASL::Mechanism +{ + class IdentifyRequest : public ::IdentifyRequest + { + Anope::string uid; + + public: + IdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : ::IdentifyRequest(m, acc, pass), uid(id) { } + + void OnSuccess() anope_override + { + if (!sasl) + return; + + NickAlias *na = NickAlias::Find(GetAccount()); + if (!na) + return OnFail(); + + SASL::Session *s = sasl->GetSession(uid); + if (s) + sasl->Succeed(s, na->nc); + } + + void OnFail() anope_override + { + if (!sasl) + return; + + SASL::Session *s = sasl->GetSession(uid); + if (s) + sasl->Fail(s); + + Log(Config->GetClient("NickServ")) << "A user failed to identify for account " << this->GetAccount() << " using SASL"; + } + }; + + public: + Plain(Module *o) : SASL::Mechanism(o, "PLAIN") { } + + void ProcessMessage(SASL::Session *sess, const SASL::Message &m) anope_override + { + if (m.type == "S") + { + sasl->SendMessage(sess, "C", "+"); + } + else if (m.type == "C") + { + Anope::string decoded; + Anope::B64Decode(m.data, decoded); + + size_t p = decoded.find('\0'); + if (p == Anope::string::npos) + return; + decoded = decoded.substr(p + 1); + + p = decoded.find('\0'); + if (p == Anope::string::npos) + return; + + Anope::string acc = decoded.substr(0, p), + pass = decoded.substr(p + 1); + + if (acc.empty() || pass.empty()) + return; + + IdentifyRequest *req = new IdentifyRequest(this->owner, m.source, acc, pass); + FOREACH_MOD(OnCheckAuthentication, (NULL, req)); + req->Dispatch(); + } + } +}; + +class External : public SASL::Mechanism +{ + struct Session : SASL::Session + { + Anope::string cert; + + Session(Mechanism *m, const Anope::string &u) : SASL::Session(m, u) { } + }; + + public: + External(Module *o) : SASL::Mechanism(o, "EXTERNAL") + { + if (!IRCD || !IRCD->CanCertFP) + throw ModuleException("No CertFP"); + } + + SASL::Session* CreateSession(const Anope::string &uid) anope_override + { + return new Session(this, uid); + } + + void ProcessMessage(SASL::Session *sess, const SASL::Message &m) anope_override + { + Session *mysess = anope_dynamic_static_cast<Session *>(sess); + + if (m.type == "S") + { + mysess->cert = m.ext; + + sasl->SendMessage(sess, "C", "+"); + } + else if (m.type == "C") + { + Anope::string account; + Anope::B64Decode(m.data, account); + + NickAlias *na = NickAlias::Find(account); + if (!na) + { + sasl->Fail(sess); + return; + } + + NSCertList *cl = na->nc->GetExt<NSCertList>("certificates"); + if (cl == NULL || !cl->FindCert(mysess->cert)) + { + sasl->Fail(sess); + return; + } + + sasl->Succeed(sess, na->nc); + } + } +}; + +class SASLService : public SASL::Service, public Timer +{ + std::map<Anope::string, SASL::Session *> sessions; + + public: + SASLService(Module *o) : SASL::Service(o), Timer(o, 60, Anope::CurTime, true) { } + + ~SASLService() + { + for (std::map<Anope::string, SASL::Session *>::iterator it = sessions.begin(); it != sessions.end();) + delete it->second; + } + + void ProcessMessage(const SASL::Message &m) anope_override + { + if (m.target != "*") + { + Server *s = Server::Find(m.target); + if (s != Me) + { + User *u = User::Find(m.target); + if (!u || u->server != Me) + return; + } + } + + SASL::Session* &session = sessions[m.source]; + + if (m.type == "S") + { + ServiceReference<SASL::Mechanism> mech("SASL::Mechanism", m.data); + if (!mech) + { + SASL::Session tmp(NULL, m.source); + + sasl->SendMechs(&tmp); + sasl->Fail(&tmp); + return; + } + + if (!session) + session = mech->CreateSession(m.source); + } + else if (m.type == "D") + { + delete session; + sessions.erase(m.source); + return; + } + + if (session && session->mech) + session->mech->ProcessMessage(session, m); + } + + Anope::string GetAgent() anope_override + { + Anope::string agent = Config->GetModule(Service::owner)->Get<Anope::string>("agent", "NickServ"); + BotInfo *bi = Config->GetClient(agent); + if (bi) + agent = bi->GetUID(); + return agent; + } + + SASL::Session* GetSession(const Anope::string &uid) anope_override + { + std::map<Anope::string, SASL::Session *>::iterator it = sessions.find(uid); + if (it != sessions.end()) + return it->second; + return NULL; + } + + void SendMessage(SASL::Session *session, const Anope::string &mtype, const Anope::string &data) anope_override + { + SASL::Message msg; + msg.source = this->GetAgent(); + msg.target = session->uid; + msg.type = mtype; + msg.data = data; + + IRCD->SendSASLMessage(msg); + } + + void Succeed(SASL::Session *session, NickCore *nc) anope_override + { + IRCD->SendSVSLogin(session->uid, nc->display); + this->SendMessage(session, "D", "S"); + } + + void Fail(SASL::Session *session) anope_override + { + this->SendMessage(session, "D", "F"); + } + + void SendMechs(SASL::Session *session) anope_override + { + std::vector<Anope::string> mechs = Service::GetServiceKeys("SASL::Mechanism"); + Anope::string buf; + for (unsigned j = 0; j < mechs.size(); ++j) + buf += "," + mechs[j]; + + this->SendMessage(session, "M", buf.empty() ? "" : buf.substr(1)); + } + + void Tick(time_t) anope_override + { + for (std::map<Anope::string, SASL::Session *>::iterator it = sessions.begin(); it != sessions.end();) + { + Anope::string key = it->first; + SASL::Session *s = it->second; + ++it; + + if (!s || !s->mech || s->created + 60 < Anope::CurTime) + { + delete s; + sessions.erase(key); + } + } + } +}; + +class ModuleSASL : public Module +{ + SASLService sasl; + + Plain plain; + External *external; + + public: + ModuleSASL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), + sasl(this), plain(this), external(NULL) + { + try + { + external = new External(this); + } + catch (ModuleException &) { } + } + + ~ModuleSASL() + { + delete external; + } +}; + +MODULE_INIT(ModuleSASL) diff --git a/modules/protocol/charybdis.cpp b/modules/protocol/charybdis.cpp index b1d2e6614..e9ea89673 100644 --- a/modules/protocol/charybdis.cpp +++ b/modules/protocol/charybdis.cpp @@ -11,8 +11,8 @@ #include "module.h" #include "modules/cs_mode.h" +#include "modules/sasl.h" -static bool sasl = true; static Anope::string UplinkSID; static ServiceReference<IRCDProto> ratbox("IRCDProto", "ratbox"); @@ -140,6 +140,18 @@ class CharybdisProto : public IRCDProto { this->SendVhost(u, "", u->host); } + + void SendSASLMessage(const SASL::Message &message) anope_override + { + Server *s = Server::Find(message.target.substr(0, 3)); + UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : message.target.substr(0, 3)) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext)); + } + + void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override + { + Server *s = Server::Find(uid.substr(0, 3)); + UplinkSocket::Message(Me) << "ENCAP " << (s ? s->GetName() : uid.substr(0, 3)) << " SVSLOGIN " << uid << " * * * " << acc; + } }; @@ -176,87 +188,16 @@ struct IRCDMessageEncap : IRCDMessage * * Charybdis only accepts messages from SASL agents; these must have umode +S */ - if (params[1] == "SASL" && sasl && params.size() == 6) + if (params[1] == "SASL" && sasl && params.size() >= 6) { - class CharybdisSASLIdentifyRequest : public IdentifyRequest - { - Anope::string uid; - MessageSource msource; - - public: - CharybdisSASLIdentifyRequest(Module *m, MessageSource &source_, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id), msource(source_) { } - - void OnSuccess() anope_override - { - BotInfo *NickServ = Config->GetClient("NickServ"); - if (!NickServ) - return; - - Anope::string accountname = GetAccount(); - NickAlias *na = NickAlias::Find(accountname); - if (na) - accountname = na->nc->display; - - /* SVSLOGIN - * parameters: target, new nick, new username, new visible hostname, new login name - * Sent after successful SASL authentication. - * The target is a UID, typically an unregistered one. - * Any of the "new" parameters can be '*' to leave the corresponding field - * unchanged. The new login name can be '0' to log the user out. - * If the UID is registered on the network, a SIGNON with the changes will be - * broadcast, otherwise the changes will be stored, to be used when registration - * completes. - */ - UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SVSLOGIN " << this->uid << " * * * " << accountname; - UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SASL " << NickServ->GetUID() << " " << this->uid << " D S"; - } - - void OnFail() anope_override - { - BotInfo *NickServ = Config->GetClient("NickServ"); - if (!NickServ) - return; - - UplinkSocket::Message(Me) << "ENCAP " << msource.GetName() << " SASL " << NickServ->GetUID() << " " << this->uid << " " << " D F"; - - Log(NickServ) << "A user failed to identify for account " << this->GetAccount() << " using SASL"; - } - }; - if (params[4] == "S") - { - BotInfo *NickServ = Config->GetClient("NickServ"); - if (!NickServ) - return; - - if (params[5] == "PLAIN") - UplinkSocket::Message(Me) << "ENCAP " << source.GetName() << " SASL " << NickServ->GetUID() << " " << params[2] << " C +"; - else - UplinkSocket::Message(Me) << "ENCAP " << source.GetName() << " SASL " << NickServ->GetUID() << " " << params[2] << " D F"; - } - else if (params[4] == "C") - { - Anope::string decoded; - Anope::B64Decode(params[5], decoded); - - size_t p = decoded.find('\0'); - if (p == Anope::string::npos) - return; - decoded = decoded.substr(p + 1); - - p = decoded.find('\0'); - if (p == Anope::string::npos) - return; - - Anope::string acc = decoded.substr(0, p), - pass = decoded.substr(p + 1); - - if (acc.empty() || pass.empty()) - return; - - IdentifyRequest *req = new CharybdisSASLIdentifyRequest(this->owner, source, params[2], acc, pass); - FOREACH_MOD(OnCheckAuthentication, (NULL, req)); - req->Dispatch(); - } + SASL::Message m; + m.source = params[2]; + m.target = params[3]; + m.type = params[4]; + m.data = params[5]; + m.ext = params.size() > 6 ? params[6] : ""; + + sasl->ProcessMessage(m); } } }; @@ -422,7 +363,6 @@ class ProtoCharybdis : public Module void OnReload(Configuration::Conf *conf) anope_override { use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); - sasl = conf->GetModule(this)->Get<bool>("sasl"); } void OnChannelSync(Channel *c) anope_override diff --git a/modules/protocol/inspircd12.cpp b/modules/protocol/inspircd12.cpp index 328049c64..e64079dca 100644 --- a/modules/protocol/inspircd12.cpp +++ b/modules/protocol/inspircd12.cpp @@ -10,6 +10,7 @@ */ #include "module.h" +#include "modules/sasl.h" struct SASLUser { @@ -18,7 +19,6 @@ struct SASLUser time_t created; }; -static bool sasl = true; static std::list<SASLUser> saslusers; static Anope::string rsquit_server, rsquit_id; @@ -398,6 +398,33 @@ class InspIRCd12Proto : public IRCDProto { } + void SendSASLMessage(const SASL::Message &message) anope_override + { + UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext)); + } + + void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override + { + UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc; + + SASLUser su; + su.uid = uid; + su.acc = acc; + su.created = Anope::CurTime; + + for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();) + { + SASLUser &u = *it; + + if (u.created + 30 < Anope::CurTime || u.uid == uid) + it = saslusers.erase(it); + else + ++it; + } + + saslusers.push_back(su); + } + bool IsExtbanValid(const Anope::string &mask) anope_override { return mask.length() >= 3 && mask[1] == ':'; @@ -846,88 +873,16 @@ struct IRCDMessageEncap : IRCDMessage if (Anope::Match(Me->GetSID(), params[0]) == false) return; - if (sasl && params[1] == "SASL" && params.size() == 6) + if (sasl && params[1] == "SASL" && params.size() >= 6) { - class InspIRCDSASLIdentifyRequest : public IdentifyRequest - { - Anope::string uid; - - public: - InspIRCDSASLIdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id) { } - - void OnSuccess() anope_override - { - Anope::string accountname = GetAccount(); - NickAlias *na = NickAlias::Find(accountname); - if (na) - accountname = na->nc->display; - - UplinkSocket::Message(Me) << "METADATA " << this->uid << " accountname :" << accountname; - UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " D S"; - - SASLUser su; - su.uid = this->uid; - su.acc = this->GetAccount(); - su.created = Anope::CurTime; - - for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();) - { - SASLUser &u = *it; - - if (u.created + 30 < Anope::CurTime || u.uid == this->uid) - it = saslusers.erase(it); - else - ++it; - } - - saslusers.push_back(su); - } - - void OnFail() anope_override - { - UplinkSocket::Message(Me) << "ENCAP " << this->uid.substr(0, 3) << " SASL " << Me->GetSID() << " " << this->uid << " " << " D F"; - - Log(Config->GetClient("NickServ")) << "A user failed to identify for account " << this->GetAccount() << " using SASL"; - } - }; - - /* - Received: :869 ENCAP * SASL 869AAAAAH * S PLAIN - Sent: :00B ENCAP 869 SASL 00B 869AAAAAH C + - Received: :869 ENCAP * SASL 869AAAAAH 00B C QWRhbQBBZGFtAG1vbw== - base64(account\0account\0pass) - */ - if (params[4] == "S") - { - if (params[5] == "PLAIN") - UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " C +"; - else - UplinkSocket::Message(Me) << "ENCAP " << params[2].substr(0, 3) << " SASL " << Me->GetSID() << " " << params[2] << " D F"; - } - else if (params[4] == "C") - { - Anope::string decoded; - Anope::B64Decode(params[5], decoded); - - size_t p = decoded.find('\0'); - if (p == Anope::string::npos) - return; - decoded = decoded.substr(p + 1); - - p = decoded.find('\0'); - if (p == Anope::string::npos) - return; - - Anope::string acc = decoded.substr(0, p), - pass = decoded.substr(p + 1); - - if (acc.empty() || pass.empty()) - return; - - IdentifyRequest *req = new InspIRCDSASLIdentifyRequest(this->owner, params[2], acc, pass); - FOREACH_MOD(OnCheckAuthentication, (NULL, req)); - req->Dispatch(); - } + SASL::Message m; + m.source = params[2]; + m.target = params[3]; + m.type = params[4]; + m.data = params[5]; + m.ext = params.size() > 6 ? params[6] : ""; + + sasl->ProcessMessage(m); } } }; @@ -1407,11 +1362,6 @@ class ProtoInspIRCd12 : public Module Servers::Capab.insert("NOQUIT"); } - void OnReload(Configuration::Conf *conf) anope_override - { - sasl = conf->GetModule(this)->Get<bool>("sasl") || conf->GetModule("inspircd20")->Get<bool>("sasl"); - } - void OnUserNickChange(User *u, const Anope::string &) anope_override { /* InspIRCd 1.2 doesn't set -r on nick change, remove -r here. Note that if we have to set +r later diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp index 6ee000f68..4e88d01a8 100644 --- a/modules/protocol/inspircd20.cpp +++ b/modules/protocol/inspircd20.cpp @@ -71,6 +71,8 @@ class InspIRCd20Proto : public IRCDProto void SendLogin(User *u, NickAlias *na) anope_override { insp12->SendLogin(u, na); } void SendLogout(User *u) anope_override { insp12->SendLogout(u); } void SendChannel(Channel *c) anope_override { insp12->SendChannel(c); } + void SendSASLMessage(const SASL::Message &message) anope_override { insp12->SendSASLMessage(message); } + void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override { insp12->SendSVSLogin(uid, acc); } bool IsExtbanValid(const Anope::string &mask) anope_override { return insp12->IsExtbanValid(mask); } bool IsIdentValid(const Anope::string &ident) anope_override { return insp12->IsIdentValid(ident); } }; diff --git a/modules/protocol/unreal.cpp b/modules/protocol/unreal.cpp index 00f7cc586..e0f051aa6 100644 --- a/modules/protocol/unreal.cpp +++ b/modules/protocol/unreal.cpp @@ -11,8 +11,7 @@ #include "module.h" #include "modules/cs_mode.h" - -static bool sasl = true; +#include "modules/sasl.h" class UnrealIRCdProto : public IRCDProto { @@ -377,6 +376,23 @@ class UnrealIRCdProto : public IRCDProto } } + void SendSASLMessage(const SASL::Message &message) anope_override + { + size_t p = message.target.find('!'); + if (p == Anope::string::npos) + return; + + UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext); + } + + void SendSVSLogin(const Anope::string &uid, const Anope::string &acc) anope_override + { + size_t p = uid.find('!'); + if (p == Anope::string::npos) + return; + UplinkSocket::Message(Me) << "SVSLOGIN " << uid.substr(0, p) << " " << uid << " " << acc; + } + bool IsIdentValid(const Anope::string &ident) anope_override { if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen")) @@ -868,85 +884,22 @@ struct IRCDMessagePong : IRCDMessage struct IRCDMessageSASL : IRCDMessage { - class UnrealSASLIdentifyRequest : public IdentifyRequest - { - Anope::string uid; - - public: - UnrealSASLIdentifyRequest(Module *m, const Anope::string &id, const Anope::string &acc, const Anope::string &pass) : IdentifyRequest(m, acc, pass), uid(id) { } - - void OnSuccess() anope_override - { - size_t p = this->uid.find('!'); - if (p == Anope::string::npos) - return; - - Anope::string accountname = GetAccount(); - NickAlias *na = NickAlias::Find(accountname); - if (na) - accountname = na->nc->display; - - UplinkSocket::Message(Me) << "SVSLOGIN " << this->uid.substr(0, p) << " " << this->uid << " " << accountname; - UplinkSocket::Message() << "SASL " << this->uid.substr(0, p) << " " << this->uid << " D S"; - } + IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } - void OnFail() anope_override - { - size_t p = this->uid.find('!'); - if (p == Anope::string::npos) - return; - - UplinkSocket::Message() << "SASL " << this->uid.substr(0, p) << " " << this->uid << " D F"; - - Log(Config->GetClient("NickServ")) << "A user failed to identify for account " << this->GetAccount() << " using SASL"; - } - }; - - IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); } - - /* Received: :irc.foonet.com SASL services.localhost.net irc.foonet.com!1.57290 S PLAIN - * uid - * - * Received: :irc.foonet.com SASL services.localhost.net irc.foonet.com!3.56270 C QWRhbQBBZGFtAHF3ZXJ0eQ== - * uid base64(account\0account\0pass) - */ void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) anope_override { size_t p = params[1].find('!'); if (!sasl || p == Anope::string::npos) return; - if (params[2] == "S") - { - if (params[3] == "PLAIN") - UplinkSocket::Message() << "SASL " << params[1].substr(0, p) << " " << params[1] << " C +"; - else - UplinkSocket::Message() << "SASL " << params[1].substr(0, p) << " " << params[1] << " D F"; - } - else if (params[2] == "C") - { - Anope::string decoded; - Anope::B64Decode(params[3], decoded); - - p = decoded.find('\0'); - if (p == Anope::string::npos) - return; - decoded = decoded.substr(p + 1); - - p = decoded.find('\0'); - if (p == Anope::string::npos) - return; + SASL::Message m; + m.source = params[1]; + m.target = params[0]; + m.type = params[2]; + m.data = params[3]; + m.ext = params.size() > 4 ? params[4] : ""; - Anope::string acc = decoded.substr(0, p), - pass = decoded.substr(p + 1); - - if (acc.empty() || pass.empty()) - return; - - IdentifyRequest *req = new UnrealSASLIdentifyRequest(this->owner, params[1], acc, pass); - FOREACH_MOD(OnCheckAuthentication, (NULL, req)); - req->Dispatch(); - } + sasl->ProcessMessage(m); } }; @@ -1241,7 +1194,6 @@ class ProtoUnreal : public Module void OnReload(Configuration::Conf *conf) anope_override { use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock"); - sasl = conf->GetModule(this)->Get<bool>("sasl"); } void OnUserNickChange(User *u, const Anope::string &) anope_override |