mirror of
https://github.com/anope/anope.git
synced 2026-07-06 01:13:14 +02:00
Add SASL EXTERNAL support. Thanks to ShutterQuick for fixing and testing.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -423,6 +423,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]
|
||||
*
|
||||
|
||||
@@ -52,4 +52,5 @@ struct Exception;
|
||||
struct MemoInfo;
|
||||
struct ModeLock;
|
||||
struct Oper;
|
||||
namespace SASL { struct Message; }
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 &);
|
||||
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
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] : "";
|
||||
|
||||
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->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
|
||||
|
||||
@@ -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;
|
||||
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] : "";
|
||||
|
||||
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->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
|
||||
|
||||
@@ -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); }
|
||||
};
|
||||
|
||||
+26
-74
@@ -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;
|
||||
IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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);
|
||||
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] : "";
|
||||
|
||||
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 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
|
||||
|
||||
Reference in New Issue
Block a user