summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/commands/cs_ban.cpp36
-rw-r--r--modules/commands/cs_clone.cpp182
-rw-r--r--modules/commands/cs_kick.cpp27
-rw-r--r--modules/commands/cs_set.cpp7
-rw-r--r--modules/commands/ns_register.cpp6
-rw-r--r--modules/commands/ns_set.cpp17
-rw-r--r--modules/commands/os_sxline.cpp4
-rw-r--r--modules/extra/m_ldap.cpp621
-rw-r--r--modules/extra/m_ldap_authentication.cpp136
-rw-r--r--modules/extra/m_ssl_openssl.cpp18
-rw-r--r--modules/fantasy.cpp24
-rw-r--r--modules/m_xmlrpc.cpp4
-rw-r--r--modules/protocol/hybrid.cpp12
-rw-r--r--modules/protocol/inspircd20.cpp2
-rw-r--r--modules/pseudoclients/operserv.cpp11
15 files changed, 605 insertions, 502 deletions
diff --git a/modules/commands/cs_ban.cpp b/modules/commands/cs_ban.cpp
index 648e379e3..de6a4f40e 100644
--- a/modules/commands/cs_ban.cpp
+++ b/modules/commands/cs_ban.cpp
@@ -101,6 +101,9 @@ class CommandCSBan : public Command
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
+ Anope::string signkickformat = Config->GetModule("chanserv")->Get<Anope::string>("signkickformat", "%m (%n)");
+ signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
+
User *u = source.GetUser();
User *u2 = User::Find(target, true);
@@ -146,7 +149,10 @@ class CommandCSBan : public Command
if (block->Get<bool>("kick", "yes"))
{
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !source.AccessFor(ci).HasPriv("SIGNKICK")))
- c->Kick(ci->WhoSends(), u2, "%s (%s)", reason.c_str(), source.GetNick().c_str());
+ {
+ signkickformat = signkickformat.replace_all_cs("%m", reason);
+ c->Kick(ci->WhoSends(), u2, "%s", signkickformat.c_str());
+ }
else
c->Kick(ci->WhoSends(), u2, "%s", reason.c_str());
}
@@ -156,15 +162,18 @@ class CommandCSBan : public Command
{
bool founder = u_access.HasPriv("FOUNDER");
bool override = !founder && !u_access.HasPriv("BAN");
- Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << target;
- if (!c->HasMode(mode, target))
+ Anope::string mask = IRCD->NormalizeMask(target);
+
+ Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << mask;
+
+ if (!c->HasMode(mode, mask))
{
- c->SetMode(NULL, mode, target);
+ c->SetMode(NULL, mode, mask);
if (ban_time)
{
- new TempBan(ban_time, c, target, mode);
- source.Reply(_("Ban on \002%s\002 expires in %s."), target.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str());
+ new TempBan(ban_time, c, mask, mode);
+ source.Reply(_("Ban on \002%s\002 expires in %s."), mask.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str());
}
}
@@ -174,7 +183,8 @@ class CommandCSBan : public Command
ChanUserContainer *uc = it->second;
++it;
- if (Anope::Match(uc->user->nick, target) || Anope::Match(uc->user->GetDisplayedMask(), target))
+ Entry e(mode, mask);
+ if (e.Matches(uc->user))
{
++matched;
@@ -193,17 +203,21 @@ class CommandCSBan : public Command
{
++kicked;
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
- c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), target.c_str(), source.GetNick().c_str());
+ {
+ reason += " (Matches " + mask + ")";
+ signkickformat = signkickformat.replace_all_cs("%m", reason);
+ c->Kick(ci->WhoSends(), uc->user, "%s", signkickformat.c_str());
+ }
else
- c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), target.c_str());
+ c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), mask.c_str());
}
}
}
if (matched)
- source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, target.c_str(), c->name.c_str());
+ source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, mask.c_str(), c->name.c_str());
else
- source.Reply(_("No users on %s match %s."), c->name.c_str(), target.c_str());
+ source.Reply(_("No users on %s match %s."), c->name.c_str(), mask.c_str());
}
}
diff --git a/modules/commands/cs_clone.cpp b/modules/commands/cs_clone.cpp
index 8365091cf..cbf53e892 100644
--- a/modules/commands/cs_clone.cpp
+++ b/modules/commands/cs_clone.cpp
@@ -14,6 +14,100 @@
class CommandCSClone : public Command
{
+ void CopySetting(ChannelInfo *ci, ChannelInfo *target_ci, const Anope::string &setting)
+ {
+ if (ci->HasExt(setting))
+ target_ci->Extend<bool>(setting);
+ }
+
+ void CopyAccess(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
+ {
+ std::set<Anope::string> masks;
+ unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
+ unsigned count = 0;
+
+ for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i)
+ masks.insert(target_ci->GetAccess(i)->Mask());
+
+ for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
+ {
+ const ChanAccess *taccess = ci->GetAccess(i);
+ AccessProvider *provider = taccess->provider;
+
+ if (access_max && target_ci->GetDeepAccessCount() >= access_max)
+ break;
+
+ if (masks.count(taccess->Mask()))
+ continue;
+ masks.insert(taccess->Mask());
+
+ ChanAccess *newaccess = provider->Create();
+ newaccess->SetMask(taccess->Mask(), target_ci);
+ newaccess->creator = taccess->creator;
+ newaccess->last_seen = taccess->last_seen;
+ newaccess->created = taccess->created;
+ newaccess->AccessUnserialize(taccess->AccessSerialize());
+
+ target_ci->AddAccess(newaccess);
+
+ ++count;
+ }
+
+ source.Reply(_("%d access entries from \002%s\002 have been cloned to \002%s\002."), count, ci->name.c_str(), target_ci->name.c_str());
+ }
+
+ void CopyAkick(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
+ {
+ target_ci->ClearAkick();
+ for (unsigned i = 0; i < ci->GetAkickCount(); ++i)
+ {
+ const AutoKick *akick = ci->GetAkick(i);
+ if (akick->nc)
+ target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used);
+ else
+ target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used);
+ }
+
+ source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
+ }
+
+ void CopyBadwords(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
+ {
+ BadWords *target_badwords = target_ci->Require<BadWords>("badwords"),
+ *badwords = ci->Require<BadWords>("badwords");
+
+ if (!target_badwords || !badwords)
+ {
+ source.Reply(ACCESS_DENIED); // BotServ doesn't exist/badwords isn't loaded
+ return;
+ }
+
+ target_badwords->ClearBadWords();
+
+ for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i)
+ {
+ const BadWord *bw = badwords->GetBadWord(i);
+ target_badwords->AddBadWord(bw->word, bw->type);
+ }
+
+ badwords->Check();
+ target_badwords->Check();
+
+ source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
+ }
+
+ void CopyLevels(CommandSource &source, ChannelInfo *ci, ChannelInfo *target_ci)
+ {
+ const Anope::map<int16_t> &cilevels = ci->GetLevelEntries();
+
+ for (Anope::map<int16_t>::const_iterator it = cilevels.begin(); it != cilevels.end(); ++it)
+ {
+ target_ci->SetLevel(it->first, it->second);
+ }
+
+ source.Reply(_("All level entries from \002%s\002 have been cloned into \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
+ }
+
public:
CommandCSClone(Module *creator) : Command(creator, "chanserv/clone", 2, 3)
{
@@ -100,82 +194,36 @@ public:
else
target_ci->last_topic_setter = source.service->nick;
+ const Anope::string settings[] = { "NOAUTOOP", "CS_KEEP_MODES", "PEACE", "PERSIST", "RESTRICTED",
+ "CS_SECURE", "SECUREFOUNDER", "SECUREOPS", "SIGNKICK", "SIGNKICK_LEVEL", "CS_NO_EXPIRE" };
+
+ for (unsigned int i = 0; i < sizeof(settings) / sizeof(Anope::string); ++i)
+ CopySetting(ci, target_ci, settings[i]);
+
+ CopyAccess(source, ci, target_ci);
+ CopyAkick(source, ci, target_ci);
+ CopyBadwords(source, ci, target_ci);
+ CopyLevels(source, ci, target_ci);
+
FOREACH_MOD(OnChanRegistered, (target_ci));
- source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str());
+ source.Reply(_("All settings from \002%s\002 have been cloned to \002%s\002."), ci->name.c_str(), target_ci->name.c_str());
}
else if (what.equals_ci("ACCESS"))
{
- std::set<Anope::string> masks;
- unsigned access_max = Config->GetModule("chanserv")->Get<unsigned>("accessmax", "1024");
- unsigned count = 0;
-
- for (unsigned i = 0; i < target_ci->GetAccessCount(); ++i)
- masks.insert(target_ci->GetAccess(i)->Mask());
-
- for (unsigned i = 0; i < ci->GetAccessCount(); ++i)
- {
- const ChanAccess *taccess = ci->GetAccess(i);
- AccessProvider *provider = taccess->provider;
-
- if (access_max && target_ci->GetDeepAccessCount() >= access_max)
- break;
-
- if (masks.count(taccess->Mask()))
- continue;
- masks.insert(taccess->Mask());
-
- ChanAccess *newaccess = provider->Create();
- newaccess->SetMask(taccess->Mask(), target_ci);
- newaccess->creator = taccess->creator;
- newaccess->last_seen = taccess->last_seen;
- newaccess->created = taccess->created;
- newaccess->AccessUnserialize(taccess->AccessSerialize());
-
- target_ci->AddAccess(newaccess);
-
- ++count;
- }
-
- source.Reply(_("%d access entries from \002%s\002 have been cloned to \002%s\002."), count, channel.c_str(), target.c_str());
+ CopyAccess(source, ci, target_ci);
}
else if (what.equals_ci("AKICK"))
{
- target_ci->ClearAkick();
- for (unsigned i = 0; i < ci->GetAkickCount(); ++i)
- {
- const AutoKick *akick = ci->GetAkick(i);
- if (akick->nc)
- target_ci->AddAkick(akick->creator, akick->nc, akick->reason, akick->addtime, akick->last_used);
- else
- target_ci->AddAkick(akick->creator, akick->mask, akick->reason, akick->addtime, akick->last_used);
- }
-
- source.Reply(_("All akick entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str());
+ CopyAkick(source, ci, target_ci);
}
else if (what.equals_ci("BADWORDS"))
{
- BadWords *target_badwords = target_ci->Require<BadWords>("badwords"),
- *badwords = ci->Require<BadWords>("badwords");
-
- if (!target_badwords || !badwords)
- {
- source.Reply(ACCESS_DENIED); // BotServ doesn't exist/badwords isn't loaded
- return;
- }
-
- target_badwords->ClearBadWords();
-
- for (unsigned i = 0; i < badwords->GetBadWordCount(); ++i)
- {
- const BadWord *bw = badwords->GetBadWord(i);
- target_badwords->AddBadWord(bw->word, bw->type);
- }
-
- badwords->Check();
- target_badwords->Check();
-
- source.Reply(_("All badword entries from \002%s\002 have been cloned to \002%s\002."), channel.c_str(), target.c_str());
+ CopyBadwords(source, ci, target_ci);
+ }
+ else if (what.equals_ci("LEVELS"))
+ {
+ CopyLevels(source, ci, target_ci);
}
else
{
@@ -191,8 +239,8 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Copies all settings, access, akicks, etc from \002channel\002 to the\n"
- "\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, or \002BADWORDS\002\n"
- "then only the respective settings are cloned.\n"
+ "\002target\002 channel. If \037what\037 is \002ACCESS\002, \002AKICK\002, \002BADWORDS\002,\n"
+ "or \002LEVELS\002 then only the respective settings are cloned.\n"
"You must be the founder of \037channel\037 and \037target\037."));
return true;
}
diff --git a/modules/commands/cs_kick.cpp b/modules/commands/cs_kick.cpp
index c95445557..5b28b5f18 100644
--- a/modules/commands/cs_kick.cpp
+++ b/modules/commands/cs_kick.cpp
@@ -47,6 +47,9 @@ class CommandCSKick : public Command
if (reason.length() > reasonmax)
reason = reason.substr(0, reasonmax);
+ Anope::string signkickformat = Config->GetModule("chanserv")->Get<Anope::string>("signkickformat", "%m (%n)");
+ signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
+
AccessGroup u_access = source.AccessFor(ci);
if (!u_access.HasPriv("KICK") && !source.HasPriv("chanserv/kick"))
@@ -66,14 +69,19 @@ class CommandCSKick : public Command
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << u2->nick;
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
- c->Kick(ci->WhoSends(), u2, "%s (%s)", reason.c_str(), source.GetNick().c_str());
+ {
+ signkickformat = signkickformat.replace_all_cs("%m", reason);
+ c->Kick(ci->WhoSends(), u2, "%s", signkickformat.c_str());
+ }
else
c->Kick(ci->WhoSends(), u2, "%s", reason.c_str());
}
}
else if (u_access.HasPriv("FOUNDER"))
{
- Log(LOG_COMMAND, source, this, ci) << "for " << target;
+ Anope::string mask = IRCD->NormalizeMask(target);
+
+ Log(LOG_COMMAND, source, this, ci) << "for " << mask;
int matched = 0, kicked = 0;
for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end;)
@@ -81,7 +89,8 @@ class CommandCSKick : public Command
ChanUserContainer *uc = it->second;
++it;
- if (Anope::Match(uc->user->nick, target) || Anope::Match(uc->user->GetDisplayedMask(), target))
+ Entry e("", mask);
+ if (e.Matches(uc->user))
{
++matched;
@@ -93,16 +102,20 @@ class CommandCSKick : public Command
++kicked;
if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
- c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), target.c_str(), source.GetNick().c_str());
+ {
+ reason += " (Matches " + mask + ")";
+ signkickformat = signkickformat.replace_all_cs("%m", reason);
+ c->Kick(ci->WhoSends(), uc->user, "%s", signkickformat.c_str());
+ }
else
- c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), target.c_str());
+ c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), mask.c_str());
}
}
if (matched)
- source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, target.c_str(), c->name.c_str());
+ source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, mask.c_str(), c->name.c_str());
else
- source.Reply(_("No users on %s match %s."), c->name.c_str(), target.c_str());
+ source.Reply(_("No users on %s match %s."), c->name.c_str(), mask.c_str());
}
else
source.Reply(NICK_X_NOT_IN_USE, target.c_str());
diff --git a/modules/commands/cs_set.cpp b/modules/commands/cs_set.cpp
index afd2c3547..73bdb5a0c 100644
--- a/modules/commands/cs_set.cpp
+++ b/modules/commands/cs_set.cpp
@@ -1235,7 +1235,7 @@ class CSSet : public Module
ci->bantype = Config->GetModule(this)->Get<int>("defbantype", "2");
}
- void OnChannelCreate(Channel *c) anope_override
+ void OnChannelSync(Channel *c) anope_override
{
if (c->ci && keep_modes.HasExt(c->ci))
{
@@ -1245,11 +1245,6 @@ class CSSet : public Module
}
}
- void OnChannelSync(Channel *c) anope_override
- {
- OnChannelCreate(c);
- }
-
EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) anope_override
{
if (!c->ci || !restricted.HasExt(c->ci) || c->MatchesList(u, "EXCEPT"))
diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp
index 4793b2269..75ef5a9fb 100644
--- a/modules/commands/ns_register.cpp
+++ b/modules/commands/ns_register.cpp
@@ -170,6 +170,8 @@ class CommandNSRegister : public Command
}
}
+ unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32");
+
if (Config->GetModule("nickserv")->Get<bool>("forceemail", "yes") && email.empty())
this->OnSyntaxError(source, "");
else if (u && Anope::CurTime < u->lastnickreg + reg_delay)
@@ -178,8 +180,8 @@ class CommandNSRegister : public Command
source.Reply(NICK_ALREADY_REGISTERED, u_nick.c_str());
else if (pass.equals_ci(u_nick) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && pass.length() < 5))
source.Reply(MORE_OBSCURE_PASSWORD);
- else if (pass.length() > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"))
- source.Reply(PASSWORD_TOO_LONG);
+ else if (pass.length() > passlen)
+ source.Reply(PASSWORD_TOO_LONG, passlen);
else if (!email.empty() && !Mail::Validate(email))
source.Reply(MAIL_X_INVALID, email.c_str());
else
diff --git a/modules/commands/ns_set.cpp b/modules/commands/ns_set.cpp
index 03ebae85c..e8e7c335c 100644
--- a/modules/commands/ns_set.cpp
+++ b/modules/commands/ns_set.cpp
@@ -133,9 +133,11 @@ class CommandNSSetPassword : public Command
source.Reply(MORE_OBSCURE_PASSWORD);
return;
}
- else if (len > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"))
+
+ unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32");
+ if (len > passlen)
{
- source.Reply(PASSWORD_TOO_LONG);
+ source.Reply(PASSWORD_TOO_LONG, passlen);
return;
}
@@ -191,14 +193,17 @@ class CommandNSSASetPassword : public Command
source.Reply(_("You may not change the password of other Services Operators."));
return;
}
- else if (nc->display.equals_ci(params[1]) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && len < 5))
+
+ if (nc->display.equals_ci(params[1]) || (Config->GetBlock("options")->Get<bool>("strictpasswords") && len < 5))
{
source.Reply(MORE_OBSCURE_PASSWORD);
return;
}
- else if (len > Config->GetModule("nickserv")->Get<unsigned>("passlen", "32"))
+
+ unsigned int passlen = Config->GetModule("nickserv")->Get<unsigned>("passlen", "32");
+ if (len > passlen)
{
- source.Reply(PASSWORD_TOO_LONG);
+ source.Reply(PASSWORD_TOO_LONG, passlen);
return;
}
@@ -414,10 +419,12 @@ class CommandNSSetEmail : public Command
message = Config->GetBlock("mail")->Get<const Anope::string>("emailchange_message");
subject = subject.replace_all_cs("%e", u->Account()->email);
+ subject = subject.replace_all_cs("%E", new_email);
subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
subject = subject.replace_all_cs("%c", code);
message = message.replace_all_cs("%e", u->Account()->email);
+ message = message.replace_all_cs("%E", new_email);
message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<const Anope::string>("networkname"));
message = message.replace_all_cs("%c", code);
diff --git a/modules/commands/os_sxline.cpp b/modules/commands/os_sxline.cpp
index 80b7c5586..3fde89871 100644
--- a/modules/commands/os_sxline.cpp
+++ b/modules/commands/os_sxline.cpp
@@ -664,7 +664,9 @@ class CommandOSSQLine : public CommandOSSXLineBase
"connect, Services will not allow it to pursue his IRC\n"
"session.\n"
"If the first character of the mask is #, services will\n"
- "prevent the use of matching channels."));
+ "prevent the use of matching channels. If the mask is a\n"
+ "regular expression, the expression will be matched against\n"
+ "channels too."));
source.Reply(_(" \n"
"\002SQLINE ADD\002 adds the given (nick's) mask to the SQLINE\n"
"list for the given reason (which \002must\002 be given).\n"
diff --git a/modules/extra/m_ldap.cpp b/modules/extra/m_ldap.cpp
index 05d54e896..ff63be5c6 100644
--- a/modules/extra/m_ldap.cpp
+++ b/modules/extra/m_ldap.cpp
@@ -1,3 +1,14 @@
+/*
+ *
+ * (C) 2011-2015 Anope Team
+ * Contact us at team@anope.org
+ *
+ * Please read COPYING and README for further details.
+ *
+ * Based on the original code of Epona by Lara.
+ * Based on the original code of Services by Andy Church.
+ */
+
/* RequiredLibraries: ldap_r,lber */
/* RequiredWindowsLibraries: libldap_r,liblber */
@@ -5,8 +16,124 @@
#include "modules/ldap.h"
#include <ldap.h>
+class LDAPService;
static Pipe *me;
+class LDAPRequest
+{
+ public:
+ LDAPService *service;
+ LDAPInterface *inter;
+ LDAPMessage *message; /* message returned by ldap_ */
+ LDAPResult *result; /* final result */
+ struct timeval tv;
+ QueryType type;
+
+ LDAPRequest(LDAPService *s, LDAPInterface *i)
+ : service(s)
+ , inter(i)
+ , message(NULL)
+ , result(NULL)
+ {
+ type = QUERY_UNKNOWN;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ }
+
+ virtual ~LDAPRequest()
+ {
+ delete result;
+ if (inter != NULL)
+ inter->OnDelete();
+ if (message != NULL)
+ ldap_msgfree(message);
+ }
+
+ virtual int run() = 0;
+};
+
+class LDAPBind : public LDAPRequest
+{
+ Anope::string who, pass;
+
+ public:
+ LDAPBind(LDAPService *s, LDAPInterface *i, const Anope::string &w, const Anope::string &p)
+ : LDAPRequest(s, i)
+ , who(w)
+ , pass(p)
+ {
+ type = QUERY_BIND;
+ }
+
+ int run() anope_override;
+};
+
+class LDAPSearch : public LDAPRequest
+{
+ Anope::string base;
+ Anope::string filter;
+
+ public:
+ LDAPSearch(LDAPService *s, LDAPInterface *i, const Anope::string &b, const Anope::string &f)
+ : LDAPRequest(s, i)
+ , base(b)
+ , filter(f)
+ {
+ type = QUERY_SEARCH;
+ }
+
+ int run() anope_override;
+};
+
+class LDAPAdd : public LDAPRequest
+{
+ Anope::string dn;
+ LDAPMods attributes;
+
+ public:
+ LDAPAdd(LDAPService *s, LDAPInterface *i, const Anope::string &d, const LDAPMods &attr)
+ : LDAPRequest(s, i)
+ , dn(d)
+ , attributes(attr)
+ {
+ type = QUERY_ADD;
+ }
+
+ int run() anope_override;
+};
+
+class LDAPDel : public LDAPRequest
+{
+ Anope::string dn;
+
+ public:
+ LDAPDel(LDAPService *s, LDAPInterface *i, const Anope::string &d)
+ : LDAPRequest(s, i)
+ , dn(d)
+ {
+ type = QUERY_DELETE;
+ }
+
+ int run() anope_override;
+};
+
+class LDAPModify : public LDAPRequest
+{
+ Anope::string base;
+ LDAPMods attributes;
+
+ public:
+ LDAPModify(LDAPService *s, LDAPInterface *i, const Anope::string &b, const LDAPMods &attr)
+ : LDAPRequest(s, i)
+ , base(b)
+ , attributes(attr)
+ {
+ type = QUERY_MODIFY;
+ }
+
+ int run() anope_override;
+};
+
class LDAPService : public LDAPProvider, public Thread, public Condition
{
Anope::string server;
@@ -19,7 +146,8 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
time_t last_connect;
- LDAPMod **BuildMods(const LDAPMods &attributes)
+ public:
+ static LDAPMod **BuildMods(const LDAPMods &attributes)
{
LDAPMod **mods = new LDAPMod*[attributes.size() + 1];
memset(mods, 0, sizeof(LDAPMod*) * (attributes.size() + 1));
@@ -46,7 +174,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
return mods;
}
- void FreeMods(LDAPMod **mods)
+ static void FreeMods(LDAPMod **mods)
{
for (int i = 0; mods[i] != NULL; ++i)
{
@@ -58,6 +186,7 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
delete [] mods;
}
+ private:
void Reconnect()
{
/* Only try one connect a minute. It is an expensive blocking operation */
@@ -71,11 +200,18 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
}
+ void QueueRequest(LDAPRequest *r)
+ {
+ this->Lock();
+ this->queries.push_back(r);
+ this->Wakeup();
+ this->Unlock();
+ }
+
public:
- typedef std::map<LDAPQuery, std::pair<time_t, LDAPInterface *> > query_queue;
- typedef std::vector<std::pair<LDAPInterface *, LDAPResult *> > result_queue;
- query_queue queries;
- result_queue results;
+ typedef std::vector<LDAPRequest *> query_queue;
+ query_queue queries, results;
+ Mutex process_mutex; /* held when processing requests not in either queue */
LDAPService(Module *o, const Anope::string &n, const Anope::string &s, int po, const Anope::string &b, const Anope::string &p, time_t t) : LDAPProvider(o, n), server(s), port(po), admin_binddn(b), admin_pass(p), timeout(t), last_connect(0)
{
@@ -96,363 +232,210 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
~LDAPService()
{
+ /* At this point the thread has stopped so we don't need to hold process_mutex */
+
this->Lock();
- for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end; ++it)
+ for (unsigned int i = 0; i < this->queries.size(); ++i)
{
- LDAPQuery msgid = it->first;
- LDAPInterface *i = it->second.second;
+ LDAPRequest *req = this->queries[i];
- ldap_abandon_ext(this->con, msgid, NULL, NULL);
- if (i)
- i->OnDelete();
+ /* queries have no results yet */
+ req->result = new LDAPResult();
+ req->result->type = req->type;
+ req->result->error = "LDAP Interface is going away";
+ if (req->inter)
+ req->inter->OnError(*req->result);
+
+ delete req;
}
this->queries.clear();
- for (result_queue::iterator it = this->results.begin(), it_end = this->results.end(); it != it_end; ++it)
+ for (unsigned int i = 0; i < this->results.size(); ++i)
{
- LDAPInterface *i = it->first;
- LDAPResult *r = it->second;
+ LDAPRequest *req = this->results[i];
- r->error = "LDAP Interface is going away";
- if (i)
- i->OnError(*r);
+ /* even though this may have already finished successfully we return that it didn't */
+ req->result->error = "LDAP Interface is going away";
+ if (req->inter)
+ req->inter->OnError(*req->result);
- delete r;
+ delete req;
}
- this->results.clear();
this->Unlock();
ldap_unbind_ext(this->con, NULL, NULL);
}
- LDAPQuery BindAsAdmin(LDAPInterface *i)
+ void BindAsAdmin(LDAPInterface *i) anope_override
{
- return this->Bind(i, this->admin_binddn, this->admin_pass);
+ this->Bind(i, this->admin_binddn, this->admin_pass);
}
- LDAPQuery Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) anope_override
+ void Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) anope_override
{
- berval cred;
- cred.bv_val = strdup(pass.c_str());
- cred.bv_len = pass.length();
-
- LDAPQuery msgid;
- int ret = ldap_sasl_bind(con, who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, &msgid);
- free(cred.bv_val);
- if (ret != LDAP_SUCCESS)
- {
- if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
- {
- this->Reconnect();
- return this->Bind(i, who, pass);
- }
- else
- throw LDAPException(ldap_err2string(ret));
- }
-
- if (i != NULL)
- {
- this->Lock();
- this->queries[msgid] = std::make_pair(Anope::CurTime, i);
- this->Unlock();
- }
- this->Wakeup();
-
- return msgid;
+ LDAPBind *b = new LDAPBind(this, i, who, pass);
+ QueueRequest(b);
}
- LDAPQuery Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) anope_override
+ void Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) anope_override
{
if (i == NULL)
throw LDAPException("No interface");
- LDAPQuery msgid;
- int ret = ldap_search_ext(this->con, base.c_str(), LDAP_SCOPE_SUBTREE, filter.c_str(), NULL, 0, NULL, NULL, NULL, 0, &msgid);
- if (ret != LDAP_SUCCESS)
- {
- if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
- {
- this->Reconnect();
- return this->Search(i, base, filter);
- }
- else
- throw LDAPException(ldap_err2string(ret));
- }
-
- this->Lock();
- this->queries[msgid] = std::make_pair(Anope::CurTime, i);
- this->Unlock();
- this->Wakeup();
-
- return msgid;
+ LDAPSearch *s = new LDAPSearch(this, i, base, filter);
+ QueueRequest(s);
}
- LDAPQuery Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) anope_override
+ void Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) anope_override
{
- LDAPMod **mods = this->BuildMods(attributes);
- LDAPQuery msgid;
- int ret = ldap_add_ext(this->con, dn.c_str(), mods, NULL, NULL, &msgid);
- this->FreeMods(mods);
-
- if (ret != LDAP_SUCCESS)
- {
- if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
- {
- this->Reconnect();
- return this->Add(i, dn, attributes);
- }
- else
- throw LDAPException(ldap_err2string(ret));
- }
+ LDAPAdd *add = new LDAPAdd(this, i, dn, attributes);
+ QueueRequest(add);
+ }
- if (i != NULL)
- {
- this->Lock();
- this->queries[msgid] = std::make_pair(Anope::CurTime, i);
- this->Unlock();
- }
- this->Wakeup();
+ void Del(LDAPInterface *i, const Anope::string &dn) anope_override
+ {
+ LDAPDel *del = new LDAPDel(this, i, dn);
+ QueueRequest(del);
+ }
- return msgid;
+ void Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) anope_override
+ {
+ LDAPModify *mod = new LDAPModify(this, i, base, attributes);
+ QueueRequest(mod);
}
- LDAPQuery Del(LDAPInterface *i, const Anope::string &dn) anope_override
+ private:
+ void BuildReply(int res, LDAPRequest *req)
{
- LDAPQuery msgid;
- int ret = ldap_delete_ext(this->con, dn.c_str(), NULL, NULL, &msgid);
+ LDAPResult *ldap_result = req->result = new LDAPResult();
+ req->result->type = req->type;
- if (ret != LDAP_SUCCESS)
+ if (res != LDAP_SUCCESS)
{
- if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
- {
- this->Reconnect();
- return this->Del(i, dn);
- }
- else
- throw LDAPException(ldap_err2string(ret));
+ ldap_result->error = ldap_err2string(res);
+ return;
}
- if (i != NULL)
+ if (req->message == NULL)
{
- this->Lock();
- this->queries[msgid] = std::make_pair(Anope::CurTime, i);
- this->Unlock();
+ return;
}
- this->Wakeup();
- return msgid;
- }
+ /* a search result */
- LDAPQuery Modify(LDAPInterface *i, const Anope::string &base, LDAPMods &attributes) anope_override
- {
- LDAPMod **mods = this->BuildMods(attributes);
- LDAPQuery msgid;
- int ret = ldap_modify_ext(this->con, base.c_str(), mods, NULL, NULL, &msgid);
- this->FreeMods(mods);
-
- if (ret != LDAP_SUCCESS)
+ for (LDAPMessage *cur = ldap_first_message(this->con, req->message); cur; cur = ldap_next_message(this->con, cur))
{
- if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
+ LDAPAttributes attributes;
+
+ char *dn = ldap_get_dn(this->con, cur);
+ if (dn != NULL)
{
- this->Reconnect();
- return this->Modify(i, base, attributes);
+ attributes["dn"].push_back(dn);
+ ldap_memfree(dn);
+ dn = NULL;
}
- else
- throw LDAPException(ldap_err2string(ret));
- }
- if (i != NULL)
- {
- this->Lock();
- this->queries[msgid] = std::make_pair(Anope::CurTime, i);
- this->Unlock();
- }
- this->Wakeup();
-
- return msgid;
- }
-
- private:
- void Timeout()
- {
- this->Lock();
- for (query_queue::iterator it = this->queries.begin(), it_end = this->queries.end(); it != it_end;)
- {
- LDAPQuery msgid = it->first;
- time_t created = it->second.first;
- LDAPInterface *i = it->second.second;
- ++it;
+ BerElement *ber = NULL;
- if (Anope::CurTime > created + timeout)
+ for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber))
{
- LDAPResult *ldap_result = new LDAPResult();
- ldap_result->id = msgid;
- ldap_result->error = "Query timed out";
+ berval **vals = ldap_get_values_len(this->con, cur, attr);
+ int count = ldap_count_values_len(vals);
- this->queries.erase(msgid);
- this->results.push_back(std::make_pair(i, ldap_result));
+ std::vector<Anope::string> attrs;
+ for (int j = 0; j < count; ++j)
+ attrs.push_back(vals[j]->bv_val);
+ attributes[attr] = attrs;
- me->Notify();
+ ldap_value_free_len(vals);
+ ldap_memfree(attr);
}
+
+ if (ber != NULL)
+ ber_free(ber, 0);
+
+ ldap_result->messages.push_back(attributes);
}
- this->Unlock();
}
- public:
- void Run() anope_override
+ void SendRequests()
{
- while (!this->GetExitState())
- {
- if (this->queries.empty())
- {
- this->Lock();
- this->Wait();
- this->Unlock();
- continue;
- }
- else
- this->Timeout();
-
- struct timeval tv = { 1, 0 };
- LDAPMessage *result;
- int rtype = ldap_result(this->con, LDAP_RES_ANY, 1, &tv, &result);
- if (rtype <= 0)
- continue;
-
- int cur_id = ldap_msgid(result);
+ process_mutex.Lock();
- this->Lock();
-
- query_queue::iterator it = this->queries.find(cur_id);
- if (it == this->queries.end())
- {
- this->Unlock();
- ldap_msgfree(result);
- continue;
- }
- LDAPInterface *i = it->second.second;
- this->queries.erase(it);
+ query_queue q;
+ this->Lock();
+ queries.swap(q);
+ this->Unlock();
- this->Unlock();
+ if (q.empty())
+ {
+ process_mutex.Unlock();
+ return;
+ }
- LDAPResult *ldap_result = new LDAPResult();
- ldap_result->id = cur_id;
+ for (unsigned int i = 0; i < q.size(); ++i)
+ {
+ LDAPRequest *req = q[i];
+ int ret = req->run();
- for (LDAPMessage *cur = ldap_first_message(this->con, result); cur; cur = ldap_next_message(this->con, cur))
+ if (ret == LDAP_SERVER_DOWN || ret == LDAP_TIMEOUT)
{
- int cur_type = ldap_msgtype(cur);
-
- LDAPAttributes attributes;
-
- char *dn = ldap_get_dn(this->con, cur);
- if (dn != NULL)
+ /* try again */
+ try
{
- attributes["dn"].push_back(dn);
- ldap_memfree(dn);
- dn = NULL;
+ Reconnect();
}
-
- switch (cur_type)
+ catch (const LDAPException &)
{
- case LDAP_RES_BIND:
- ldap_result->type = LDAPResult::QUERY_BIND;
- break;
- case LDAP_RES_SEARCH_ENTRY:
- ldap_result->type = LDAPResult::QUERY_SEARCH;
- break;
- case LDAP_RES_ADD:
- ldap_result->type = LDAPResult::QUERY_ADD;
- break;
- case LDAP_RES_DELETE:
- ldap_result->type = LDAPResult::QUERY_DELETE;
- break;
- case LDAP_RES_MODIFY:
- ldap_result->type = LDAPResult::QUERY_MODIFY;
- break;
- case LDAP_RES_SEARCH_RESULT:
- // If we get here and ldap_result->type is LDAPResult::QUERY_UNKNOWN
- // then the result set is empty
- ldap_result->type = LDAPResult::QUERY_SEARCH;
- break;
- default:
- Log(LOG_DEBUG) << "m_ldap: Unknown msg type " << cur_type;
- continue;
}
- switch (cur_type)
- {
- case LDAP_RES_BIND:
- {
- int errcode = -1;
- int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
- if (parse_result != LDAP_SUCCESS)
- ldap_result->error = ldap_err2string(parse_result);
- else if (errcode != LDAP_SUCCESS)
- ldap_result->error = ldap_err2string(errcode);
- break;
- }
- case LDAP_RES_SEARCH_ENTRY:
- {
- BerElement *ber = NULL;
- for (char *attr = ldap_first_attribute(this->con, cur, &ber); attr; attr = ldap_next_attribute(this->con, cur, ber))
- {
- berval **vals = ldap_get_values_len(this->con, cur, attr);
- int count = ldap_count_values_len(vals);
-
- std::vector<Anope::string> attrs;
- for (int j = 0; j < count; ++j)
- attrs.push_back(vals[j]->bv_val);
- attributes[attr] = attrs;
-
- ldap_value_free_len(vals);
- ldap_memfree(attr);
- }
- if (ber != NULL)
- ber_free(ber, 0);
-
- break;
- }
- case LDAP_RES_ADD:
- case LDAP_RES_DELETE:
- case LDAP_RES_MODIFY:
- {
- int errcode = -1;
- int parse_result = ldap_parse_result(this->con, cur, &errcode, NULL, NULL, NULL, NULL, 0);
- if (parse_result != LDAP_SUCCESS)
- ldap_result->error = ldap_err2string(parse_result);
- else if (errcode != LDAP_SUCCESS)
- ldap_result->error = ldap_err2string(errcode);
- break;
- }
- default:
- continue;
- }
-
- ldap_result->messages.push_back(attributes);
+ ret = req->run();
}
- ldap_msgfree(result);
+ BuildReply(ret, req);
this->Lock();
- this->results.push_back(std::make_pair(i, ldap_result));
+ results.push_back(req);
+ this->Unlock();
+ }
+
+ me->Notify();
+
+ process_mutex.Unlock();
+ }
+
+ public:
+ void Run() anope_override
+ {
+ while (!this->GetExitState())
+ {
+ this->Lock();
+ /* Queries can be non empty if one is pushed during SendRequests() */
+ if (queries.empty())
+ this->Wait();
this->Unlock();
- me->Notify();
+ SendRequests();
}
}
+
+ LDAP* GetConnection()
+ {
+ return con;
+ }
};
class ModuleLDAP : public Module, public Pipe
{
std::map<Anope::string, LDAPService *> LDAPServices;
+
public:
ModuleLDAP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
{
me = this;
-
}
~ModuleLDAP()
@@ -489,6 +472,8 @@ class ModuleLDAP : public Module, public Pipe
s->SetExitState();
s->Wakeup();
+ s->Join();
+ delete s;
this->LDAPServices.erase(cname);
}
}
@@ -528,32 +513,36 @@ class ModuleLDAP : public Module, public Pipe
for (std::map<Anope::string, LDAPService *>::iterator it = this->LDAPServices.begin(); it != this->LDAPServices.end(); ++it)
{
LDAPService *s = it->second;
+
+ s->process_mutex.Lock();
s->Lock();
- for (LDAPService::query_queue::iterator it2 = s->queries.begin(); it2 != s->queries.end();)
+
+ for (unsigned int i = s->queries.size(); i > 0; --i)
{
- LDAPQuery msgid = it2->first;
- LDAPInterface *i = it2->second.second;
- ++it2;
+ LDAPRequest *req = s->queries[i - 1];
+ LDAPInterface *li = req->inter;
- if (i && i->owner == m)
+ if (li && li->owner == m)
{
- i->OnDelete();
- s->queries.erase(msgid);
+ s->queries.erase(s->queries.begin() + i - 1);
+ delete req;
}
}
- for (unsigned i = s->results.size(); i > 0; --i)
+ for (unsigned int i = s->results.size(); i > 0; --i)
{
- LDAPInterface *li = s->results[i - 1].first;
- LDAPResult *r = s->results[i - 1].second;
+ LDAPRequest *req = s->results[i - 1];
+ LDAPInterface *li = req->inter;
if (li && li->owner == m)
{
s->results.erase(s->results.begin() + i - 1);
- delete r;
+ delete req;
}
}
+
s->Unlock();
- }
+ s->process_mutex.Unlock();
+ }
}
void OnNotify() anope_override
@@ -562,15 +551,16 @@ class ModuleLDAP : public Module, public Pipe
{
LDAPService *s = it->second;
- LDAPService::result_queue results;
+ LDAPService::query_queue results;
s->Lock();
results.swap(s->results);
s->Unlock();
- for (unsigned i = 0; i < results.size(); ++i)
+ for (unsigned int i = 0; i < results.size(); ++i)
{
- LDAPInterface *li = results[i].first;
- LDAPResult *r = results[i].second;
+ LDAPRequest *req = results[i];
+ LDAPInterface *li = req->inter;
+ LDAPResult *r = req->result;
if (li != NULL)
{
@@ -583,11 +573,50 @@ class ModuleLDAP : public Module, public Pipe
li->OnResult(*r);
}
- delete r;
+ delete req;
}
}
}
};
+int LDAPBind::run()
+{
+ berval cred;
+ cred.bv_val = strdup(pass.c_str());
+ cred.bv_len = pass.length();
+
+ int i = ldap_sasl_bind_s(service->GetConnection(), who.c_str(), LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
+
+ free(cred.bv_val);
+
+ return i;
+}
+
+int LDAPSearch::run()
+{
+ return ldap_search_ext_s(service->GetConnection(), base.c_str(), LDAP_SCOPE_SUBTREE, filter.c_str(), NULL, 0, NULL, NULL, &tv, 0, &message);
+}
+
+int LDAPAdd::run()
+{
+ LDAPMod **mods = LDAPService::BuildMods(attributes);
+ int i = ldap_add_ext_s(service->GetConnection(), dn.c_str(), mods, NULL, NULL);
+ LDAPService::FreeMods(mods);
+ return i;
+}
+
+int LDAPDel::run()
+{
+ return ldap_delete_ext_s(service->GetConnection(), dn.c_str(), NULL, NULL);
+}
+
+int LDAPModify::run()
+{
+ LDAPMod **mods = LDAPService::BuildMods(attributes);
+ int i = ldap_modify_ext_s(service->GetConnection(), base.c_str(), mods, NULL, NULL);
+ LDAPService::FreeMods(mods);
+ return i;
+}
+
MODULE_INIT(ModuleLDAP)
diff --git a/modules/extra/m_ldap_authentication.cpp b/modules/extra/m_ldap_authentication.cpp
index 01bafac45..23f47c5e6 100644
--- a/modules/extra/m_ldap_authentication.cpp
+++ b/modules/extra/m_ldap_authentication.cpp
@@ -30,36 +30,29 @@ struct IdentifyInfo
class IdentifyInterface : public LDAPInterface
{
- std::map<LDAPQuery, IdentifyInfo *> requests;
+ IdentifyInfo *ii;
public:
- IdentifyInterface(Module *m) : LDAPInterface(m) { }
+ IdentifyInterface(Module *m, IdentifyInfo *i) : LDAPInterface(m), ii(i) { }
- void Add(LDAPQuery id, IdentifyInfo *ii)
+ ~IdentifyInterface()
{
- std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(id);
- if (it != this->requests.end())
- delete it->second;
- this->requests[id] = ii;
+ delete ii;
}
- void OnResult(const LDAPResult &r) anope_override
+ void OnDelete() anope_override
{
- std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id);
- if (it == this->requests.end())
- return;
- IdentifyInfo *ii = it->second;
- this->requests.erase(it);
+ delete this;
+ }
+ void OnResult(const LDAPResult &r) anope_override
+ {
if (!ii->lprov)
- {
- delete ii;
return;
- }
switch (r.type)
{
- case LDAPResult::QUERY_SEARCH:
+ case QUERY_SEARCH:
{
if (!r.empty())
{
@@ -68,9 +61,9 @@ class IdentifyInterface : public LDAPInterface
const LDAPAttributes &attr = r.get(0);
ii->dn = attr.get("dn");
Log(LOG_DEBUG) << "m_ldap_authenticationn: binding as " << ii->dn;
- LDAPQuery id = ii->lprov->Bind(this, ii->dn, ii->req->GetPassword());
- this->Add(id, ii);
- return;
+
+ ii->lprov->Bind(new IdentifyInterface(this->owner, ii), ii->dn, ii->req->GetPassword());
+ ii = NULL;
}
catch (const LDAPException &ex)
{
@@ -79,7 +72,7 @@ class IdentifyInterface : public LDAPInterface
}
break;
}
- case LDAPResult::QUERY_BIND:
+ case QUERY_BIND:
{
if (ii->admin_bind)
{
@@ -87,10 +80,9 @@ class IdentifyInterface : public LDAPInterface
try
{
Log(LOG_DEBUG) << "m_ldap_authentication: searching for " << sf;
- LDAPQuery id = ii->lprov->Search(this, basedn, sf);
- this->Add(id, ii);
+ ii->lprov->Search(new IdentifyInterface(this->owner, ii), basedn, sf);
ii->admin_bind = false;
- return;
+ ii = NULL;
}
catch (const LDAPException &ex)
{
@@ -120,40 +112,28 @@ class IdentifyInterface : public LDAPInterface
default:
break;
}
-
- delete ii;
}
void OnError(const LDAPResult &r) anope_override
{
- std::map<LDAPQuery, IdentifyInfo *>::iterator it = this->requests.find(r.id);
- if (it == this->requests.end())
- return;
- IdentifyInfo *ii = it->second;
- this->requests.erase(it);
- delete ii;
}
};
class OnIdentifyInterface : public LDAPInterface
{
- std::map<LDAPQuery, Anope::string> requests;
+ Anope::string uid;
public:
- OnIdentifyInterface(Module *m) : LDAPInterface(m) { }
+ OnIdentifyInterface(Module *m, const Anope::string &i) : LDAPInterface(m), uid(i) { }
- void Add(LDAPQuery id, const Anope::string &nick)
+ void OnDelete() anope_override
{
- this->requests[id] = nick;
+ delete this;
}
void OnResult(const LDAPResult &r) anope_override
{
- std::map<LDAPQuery, Anope::string>::iterator it = this->requests.find(r.id);
- if (it == this->requests.end())
- return;
- User *u = User::Find(it->second);
- this->requests.erase(it);
+ User *u = User::Find(uid);
if (!u || !u->Account() || r.empty())
return;
@@ -180,7 +160,6 @@ class OnIdentifyInterface : public LDAPInterface
void OnError(const LDAPResult &r) anope_override
{
- this->requests.erase(r.id);
Log(this->owner) << r.error;
}
};
@@ -201,11 +180,9 @@ class OnRegisterInterface : public LDAPInterface
}
};
-class NSIdentifyLDAP : public Module
+class ModuleLDAPAuthentication : public Module
{
ServiceReference<LDAPProvider> ldap;
- IdentifyInterface iinterface;
- OnIdentifyInterface oninterface;
OnRegisterInterface orinterface;
PrimitiveExtensibleItem<Anope::string> dn;
@@ -214,11 +191,10 @@ class NSIdentifyLDAP : public Module
Anope::string disable_register_reason;
Anope::string disable_email_reason;
public:
- NSIdentifyLDAP(const Anope::string &modname, const Anope::string &creator) :
- Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), iinterface(this), oninterface(this), orinterface(this),
+ ModuleLDAPAuthentication(const Anope::string &modname, const Anope::string &creator) :
+ Module(modname, creator, EXTRA | VENDOR), ldap("LDAPProvider", "ldap/main"), orinterface(this),
dn(this, "m_ldap_authentication_dn")
{
-
me = this;
}
@@ -271,16 +247,7 @@ class NSIdentifyLDAP : public Module
return;
IdentifyInfo *ii = new IdentifyInfo(u, req, this->ldap);
- try
- {
- LDAPQuery id = this->ldap->BindAsAdmin(&this->iinterface);
- this->iinterface.Add(id, ii);
- }
- catch (const LDAPException &ex)
- {
- delete ii;
- Log(this) << ex.GetReason();
- }
+ this->ldap->BindAsAdmin(new IdentifyInterface(this, ii));
}
void OnNickIdentify(User *u) anope_override
@@ -292,15 +259,7 @@ class NSIdentifyLDAP : public Module
if (!d || d->empty())
return;
- try
- {
- LDAPQuery id = this->ldap->Search(&this->oninterface, *d, "(" + email_attribute + "=*)");
- this->oninterface.Add(id, u->nick);
- }
- catch (const LDAPException &ex)
- {
- Log(this) << ex.GetReason();
- }
+ this->ldap->Search(new OnIdentifyInterface(this, u->GetUID()), *d, "(" + email_attribute + "=*)");
}
void OnNickRegister(User *, NickAlias *na, const Anope::string &pass) anope_override
@@ -308,37 +267,30 @@ class NSIdentifyLDAP : public Module
if (!this->disable_register_reason.empty() || !this->ldap)
return;
- try
- {
- this->ldap->BindAsAdmin(NULL);
-
- LDAPMods attributes;
- attributes.resize(4);
-
- attributes[0].name = "objectClass";
- attributes[0].values.push_back("top");
- attributes[0].values.push_back(object_class);
+ this->ldap->BindAsAdmin(NULL);
- attributes[1].name = username_attribute;
- attributes[1].values.push_back(na->nick);
+ LDAPMods attributes;
+ attributes.resize(4);
- if (!na->nc->email.empty())
- {
- attributes[2].name = email_attribute;
- attributes[2].values.push_back(na->nc->email);
- }
+ attributes[0].name = "objectClass";
+ attributes[0].values.push_back("top");
+ attributes[0].values.push_back(object_class);
- attributes[3].name = this->password_attribute;
- attributes[3].values.push_back(pass);
+ attributes[1].name = username_attribute;
+ attributes[1].values.push_back(na->nick);
- Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn;
- this->ldap->Add(&this->orinterface, new_dn, attributes);
- }
- catch (const LDAPException &ex)
+ if (!na->nc->email.empty())
{
- Log(this) << ex.GetReason();
+ attributes[2].name = email_attribute;
+ attributes[2].values.push_back(na->nc->email);
}
+
+ attributes[3].name = this->password_attribute;
+ attributes[3].values.push_back(pass);
+
+ Anope::string new_dn = username_attribute + "=" + na->nick + "," + basedn;
+ this->ldap->Add(&this->orinterface, new_dn, attributes);
}
};
-MODULE_INIT(NSIdentifyLDAP)
+MODULE_INIT(ModuleLDAPAuthentication)
diff --git a/modules/extra/m_ssl_openssl.cpp b/modules/extra/m_ssl_openssl.cpp
index ebf88ad63..c26c63655 100644
--- a/modules/extra/m_ssl_openssl.cpp
+++ b/modules/extra/m_ssl_openssl.cpp
@@ -103,6 +103,10 @@ class SSLModule : public Module
if (!client_ctx || !server_ctx)
throw ModuleException("Error initializing SSL CTX");
+ long opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_CIPHER_SERVER_PREFERENCE;
+ SSL_CTX_set_options(client_ctx, opts);
+ SSL_CTX_set_options(server_ctx, opts);
+
SSL_CTX_set_mode(client_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
SSL_CTX_set_mode(server_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
@@ -158,6 +162,20 @@ class SSLModule : public Module
Log() << "Unable to open private key " << this->keyfile;
}
+ // Allow disabling SSLv3
+ if (!config->Get<Anope::string>("sslv3").empty())
+ {
+ if (config->Get<bool>("sslv3"))
+ {
+ SSL_CTX_clear_options(client_ctx, SSL_OP_NO_SSLv3);
+ SSL_CTX_clear_options(server_ctx, SSL_OP_NO_SSLv3);
+ }
+ else
+ {
+ SSL_CTX_set_options(client_ctx, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(server_ctx, SSL_OP_NO_SSLv3);
+ }
+ }
}
void OnPreServerConnect() anope_override
diff --git a/modules/fantasy.cpp b/modules/fantasy.cpp
index 58226699c..1bda6c106 100644
--- a/modules/fantasy.cpp
+++ b/modules/fantasy.cpp
@@ -103,12 +103,28 @@ class Fantasy : public Module
std::vector<Anope::string> params;
spacesepstream(msg).GetTokens(params);
- if (!msg.find(c->ci->bi->nick))
+ if (params.empty())
+ return;
+
+ Anope::string normalized_param0 = Anope::NormalizeBuffer(params[0]);
+ Anope::string fantasy_chars = Config->GetModule(this)->Get<Anope::string>("fantasycharacter", "!");
+
+ if (!normalized_param0.find(c->ci->bi->nick))
+ {
params.erase(params.begin());
- else if (!msg.find_first_of(Config->GetModule(this)->Get<const Anope::string>("fantasycharacter", "!")))
- params[0].erase(params[0].begin());
+ }
+ else if (!normalized_param0.find_first_of(fantasy_chars))
+ {
+ size_t sz = params[0].find_first_of(fantasy_chars);
+ if (sz == Anope::string::npos)
+ return; /* normalized_param0 is a subset of params[0] so this can't happen */
+
+ params[0].erase(0, sz + 1);
+ }
else
+ {
return;
+ }
if (params.empty())
return;
@@ -123,7 +139,7 @@ class Fantasy : public Module
full_command.erase(full_command.begin());
++count;
- it = Config->Fantasy.find(full_command);
+ it = Config->Fantasy.find(Anope::NormalizeBuffer(full_command));
}
if (it == Config->Fantasy.end())
diff --git a/modules/m_xmlrpc.cpp b/modules/m_xmlrpc.cpp
index 2fd900e61..01300fbbb 100644
--- a/modules/m_xmlrpc.cpp
+++ b/modules/m_xmlrpc.cpp
@@ -179,10 +179,10 @@ class MyXMLRPCServiceInterface : public XMLRPCServiceInterface, public HTTPPage
if (!request.id.empty())
request.reply("id", request.id);
- Anope::string r = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<methodCall>\n<methodName>" + request.name + "</methodName>\n<params>\n<param>\n<value>\n<struct>\n";
+ Anope::string r = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<methodResponse>\n<methodName>" + request.name + "</methodName>\n<params>\n<param>\n<value>\n<struct>\n";
for (std::map<Anope::string, Anope::string>::const_iterator it = request.get_replies().begin(); it != request.get_replies().end(); ++it)
r += "<member>\n<name>" + it->first + "</name>\n<value>\n<string>" + this->Sanitize(it->second) + "</string>\n</value>\n</member>\n";
- r += "</struct>\n</value>\n</param>\n</params>\n</methodCall>";
+ r += "</struct>\n</value>\n</param>\n</params>\n</methodResponse>";
request.r.Write(r);
}
diff --git a/modules/protocol/hybrid.cpp b/modules/protocol/hybrid.cpp
index 5c612eba5..150886232 100644
--- a/modules/protocol/hybrid.cpp
+++ b/modules/protocol/hybrid.cpp
@@ -36,7 +36,7 @@ class HybridProto : public IRCDProto
}
public:
- HybridProto(Module *creator) : IRCDProto(creator, "Hybrid 8.1.x")
+ HybridProto(Module *creator) : IRCDProto(creator, "Hybrid 8.2.x")
{
DefaultPseudoclientModes = "+oi";
CanSVSNick = true;
@@ -204,7 +204,7 @@ class HybridProto : public IRCDProto
SendServer(Me);
- UplinkSocket::Message() << "SVINFO 6 5 0 :" << Anope::CurTime;
+ UplinkSocket::Message() << "SVINFO 6 6 0 :" << Anope::CurTime;
}
void SendClientIntroduction(User *u) anope_override
@@ -212,7 +212,7 @@ class HybridProto : public IRCDProto
Anope::string modes = "+" + u->GetModes();
UplinkSocket::Message(Me) << "UID " << u->nick << " 1 " << u->timestamp << " " << modes << " "
- << u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " 0 :" << u->realname;
+ << u->GetIdent() << " " << u->host << " 0 " << u->GetUID() << " * :" << u->realname;
}
void SendEOB() anope_override
@@ -252,7 +252,7 @@ class HybridProto : public IRCDProto
void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) anope_override
{
- UplinkSocket::Message(Me) << "SVSNICK " << u->nick << " " << newnick << " " << when;
+ UplinkSocket::Message(Me) << "SVSNICK " << u->GetUID() << " " << newnick << " " << when;
}
void SendSVSJoin(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string &) anope_override
@@ -541,7 +541,7 @@ struct IRCDMessageUID : IRCDMessage
IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 10) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
/* 0 1 2 3 4 5 6 7 8 9 */
- /* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB 1350157108 :Mining all the time */
+ /* :0MC UID Steve 1 1350157102 +oi ~steve resolved.host 10.0.0.1 0MCAAAAAB Steve :Mining all the time */
void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
{
Anope::string ip = params[6];
@@ -550,7 +550,7 @@ struct IRCDMessageUID : IRCDMessage
ip.clear();
NickAlias *na = NULL;
- if (params[8] != "0")
+ if (params[8] != "0" && params[8] != "*")
na = NickAlias::Find(params[8]);
/* Source is always the server */
diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp
index 9130c4354..d95f09591 100644
--- a/modules/protocol/inspircd20.cpp
+++ b/modules/protocol/inspircd20.cpp
@@ -789,9 +789,9 @@ struct IRCDMessageFHost : IRCDMessage
void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
{
User *u = source.GetUser();
- u->SetDisplayedHost(params[0]);
if (u->HasMode("CLOAK"))
u->RemoveModeInternal(source, ModeManager::FindUserModeByName("CLOAK"));
+ u->SetDisplayedHost(params[0]);
}
};
diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp
index 67eaecd45..439c33708 100644
--- a/modules/pseudoclients/operserv.cpp
+++ b/modules/pseudoclients/operserv.cpp
@@ -117,13 +117,20 @@ class SQLineManager : public XLineManager
for (std::vector<XLine *>::const_iterator it = this->GetList().begin(), it_end = this->GetList().end(); it != it_end; ++it)
{
XLine *x = *it;
+
if (x->regex)
{
if (x->regex->Matches(c->name))
return x;
}
- else if (Anope::Match(c->name, x->mask, false, true))
- return x;
+ else
+ {
+ if (x->mask.empty() || x->mask[0] != '#')
+ continue;
+
+ if (Anope::Match(c->name, x->mask, false, true))
+ return x;
+ }
}
return NULL;
}