summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/commands/bs_bot.cpp12
-rw-r--r--modules/commands/cs_access.cpp12
-rw-r--r--modules/commands/cs_ban.cpp39
-rw-r--r--modules/commands/cs_clone.cpp16
-rw-r--r--modules/commands/cs_entrymsg.cpp12
-rw-r--r--modules/commands/cs_kick.cpp28
-rw-r--r--modules/commands/cs_mode.cpp40
-rw-r--r--modules/commands/cs_set.cpp26
-rw-r--r--modules/commands/cs_topic.cpp6
-rw-r--r--modules/commands/hs_del.cpp3
-rw-r--r--modules/commands/hs_group.cpp2
-rw-r--r--modules/commands/hs_list.cpp2
-rw-r--r--modules/commands/hs_off.cpp4
-rw-r--r--modules/commands/hs_on.cpp3
-rw-r--r--modules/commands/hs_set.cpp3
-rw-r--r--modules/commands/ms_read.cpp4
-rw-r--r--modules/commands/ms_set.cpp2
-rw-r--r--modules/commands/ns_alist.cpp2
-rw-r--r--modules/commands/ns_identify.cpp8
-rw-r--r--modules/commands/ns_logout.cpp2
-rw-r--r--modules/commands/ns_register.cpp8
-rw-r--r--modules/commands/ns_set.cpp2
-rw-r--r--modules/commands/os_mode.cpp14
-rw-r--r--modules/database/db_flatfile.cpp2
-rw-r--r--modules/database/db_old.cpp2
-rw-r--r--modules/extra/m_ldap.cpp665
-rw-r--r--modules/extra/m_ldap_authentication.cpp152
-rw-r--r--modules/extra/m_ldap_oper.cpp43
-rw-r--r--modules/extra/m_ssl_openssl.cpp18
-rw-r--r--modules/extra/stats/irc2sql/irc2sql.cpp11
-rw-r--r--modules/extra/stats/irc2sql/irc2sql.h3
-rw-r--r--modules/extra/stats/m_chanstats.cpp9
-rw-r--r--modules/fantasy.cpp28
-rw-r--r--modules/m_dns.cpp16
-rw-r--r--modules/m_xmlrpc.cpp50
-rw-r--r--modules/protocol/bahamut.cpp8
-rw-r--r--modules/protocol/charybdis.cpp4
-rw-r--r--modules/protocol/hybrid.cpp27
-rw-r--r--modules/protocol/inspircd20.cpp58
-rw-r--r--modules/protocol/ngircd.cpp14
-rw-r--r--modules/protocol/ratbox.cpp4
-rw-r--r--modules/protocol/unreal.cpp10
-rw-r--r--modules/pseudoclients/botserv/botserv.cpp6
-rw-r--r--modules/pseudoclients/chanserv/channel.cpp17
-rw-r--r--modules/pseudoclients/chanserv/channel.h4
-rw-r--r--modules/pseudoclients/nickserv/nickserv.cpp44
-rw-r--r--modules/pseudoclients/operserv.cpp8
-rw-r--r--modules/webcpanel/pages/index.cpp6
48 files changed, 846 insertions, 613 deletions
diff --git a/modules/commands/bs_bot.cpp b/modules/commands/bs_bot.cpp
index 1ba22531e..726c02ab2 100644
--- a/modules/commands/bs_bot.cpp
+++ b/modules/commands/bs_bot.cpp
@@ -82,7 +82,10 @@ class CommandBSBot : public Command
User *targ = User::Find(nick, true);
if (targ)
- targ->Kill(Me, "Nickname is reserved for services");
+ {
+ source.Reply(_("\002{0}\002 is currently in use."), targ->nick);
+ return;
+ }
ServiceBot *bi = new ServiceBot(nick, user, host, real);
@@ -179,6 +182,13 @@ class CommandBSBot : public Command
return;
}
+ User *target = User::Find(nick, true);
+ if (target)
+ {
+ source.Reply(_("\002{0}\002 is currently in use."), target->nick);
+ return;
+ }
+
if (!nick.equals_ci(bi->nick))
{
/* We check whether the nick is registered, and inform the user
diff --git a/modules/commands/cs_access.cpp b/modules/commands/cs_access.cpp
index 982d5763f..f8ecc6c38 100644
--- a/modules/commands/cs_access.cpp
+++ b/modules/commands/cs_access.cpp
@@ -704,7 +704,7 @@ class CommandCSLevels : public Command
{
const Anope::string &what = params[2];
- /* Don't allow disabling of the founder level. It would be hard to change it back if you dont have access to use this command */
+ /* Don't allow disabling of the founder level. It would be hard to change it back if you don't have access to use this command */
if (what.equals_ci("FOUNDER"))
{
source.Reply(_("You can not disable the founder privilege because it would be impossible to reenable it at a later time."));
@@ -804,6 +804,14 @@ class CommandCSLevels : public Command
return;
}
+ bool has_access = false;
+ if (source.HasPriv("chanserv/access/modify"))
+ has_access = true;
+ else if (cmd.equals_ci("LIST") && source.HasPriv("chanserv/access/list"))
+ has_access = true;
+ else if (source.AccessFor(ci).HasPriv("FOUNDER"))
+ has_access = true;
+
/* If SET, we want two extra parameters; if DIS[ABLE] or FOUNDER, we want only
* one; else, we want none.
*/
@@ -813,7 +821,7 @@ class CommandCSLevels : public Command
return;
}
- if (!source.AccessFor(ci).HasPriv("FOUNDER") && !source.HasPriv("chanserv/access/modify"))
+ if (!has_access)
{
source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "FOUNDER", ci->GetName());
return;
diff --git a/modules/commands/cs_ban.cpp b/modules/commands/cs_ban.cpp
index a17ae48a0..f797eda0f 100644
--- a/modules/commands/cs_ban.cpp
+++ b/modules/commands/cs_ban.cpp
@@ -102,6 +102,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);
@@ -124,7 +127,7 @@ class CommandCSBan : public Command
}
/*
- * Dont ban/kick the user on channels where he is excepted
+ * Don't ban/kick the user on channels where he is excepted
* to prevent services <-> server wars.
*/
if (c->MatchesList(u2, "EXCEPT"))
@@ -161,7 +164,10 @@ class CommandCSBan : public Command
if (block->Get<bool>("kick", "yes"))
{
if (ci->HasFieldS("SIGNKICK") || (ci->HasFieldS("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());
}
@@ -170,15 +176,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{0}\002 expires in \002{1}\002."), target, Anope::Duration(ban_time, source.GetAccount()));
+ new TempBan(ban_time, c, mask, mode);
+ source.Reply(_("Ban on \002{0}\002 expires in \002{1}\002."), mask, Anope::Duration(ban_time, source.GetAccount()));
}
}
@@ -188,7 +197,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;
@@ -206,18 +216,23 @@ class CommandCSBan : public Command
if (block->Get<bool>("kick", "yes"))
{
++kicked;
+
if (ci->HasFieldS("SIGNKICK") || (ci->HasFieldS("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 \002{0}/{1}\002 users matching \002{2}\002 from \002{3}\002."), kicked, matched, target, c->name);
+ source.Reply(_("Kicked \002{0}/{1}\002 users matching \002{2}\002 from \002{3}\002."), kicked, matched, mask, c->name);
else
- source.Reply(_("No users on \002{0}\002 match \002{1}\002."), c->name, target);
+ source.Reply(_("No users on \002{0}\002 match \002{1}\002."), c->name, mask);
}
}
diff --git a/modules/commands/cs_clone.cpp b/modules/commands/cs_clone.cpp
index 69dc70bea..256446bd1 100644
--- a/modules/commands/cs_clone.cpp
+++ b/modules/commands/cs_clone.cpp
@@ -15,6 +15,20 @@
class CommandCSClone : public Command
{
+#if 0
+ 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());
+ }
+#endif
+
public:
CommandCSClone(Module *creator) : Command(creator, "chanserv/clone", 2, 3)
{
@@ -73,7 +87,7 @@ public:
if (what.empty())
{
- delete target_ci;
+ target_ci->Delete();
target_ci = ChanServ::channel.Create();
target_ci->SetName(target);
ChanServ::registered_channel_map& map = ChanServ::service->GetChannels();
diff --git a/modules/commands/cs_entrymsg.cpp b/modules/commands/cs_entrymsg.cpp
index 4a646b3b3..31253599e 100644
--- a/modules/commands/cs_entrymsg.cpp
+++ b/modules/commands/cs_entrymsg.cpp
@@ -138,7 +138,7 @@ class CommandEntryMessage : public Command
msg->SetChannel(ci);
msg->SetCreator(source.GetNick());
msg->SetMessage(message);
- Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to add a message";
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to add a message";
source.Reply(_("Entry message added to \002{0}\002"), ci->GetName());
}
@@ -157,8 +157,8 @@ class CommandEntryMessage : public Command
unsigned i = convertTo<unsigned>(message);
if (i > 0 && i <= messages.size())
{
- delete messages[i - 1];
- Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove a message";
+ messages[i - 1]->Delete();
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove a message";
source.Reply(_("Entry message \002{0}\002 for \002{1]\002 deleted."), i, ci->GetName());
}
else
@@ -176,7 +176,7 @@ class CommandEntryMessage : public Command
for (EntryMsg *e : ci->GetRefs<EntryMsg *>(entrymsg))
delete e;
- Log(source.IsFounder(ci) ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove all messages";
+ Log(source.AccessFor(ci).HasPriv("SET") ? LOG_COMMAND : LOG_OVERRIDE, source, this, ci) << "to remove all messages";
source.Reply(_("Entry messages for \002{0}\002 have been cleared."), ci->GetName());
}
@@ -207,7 +207,7 @@ class CommandEntryMessage : public Command
return;
}
- if (!source.IsFounder(ci) && !source.HasPriv("chanserv/administration"))
+ if (!source.AccessFor(ci).HasPriv("SET") && !source.HasPriv("chanserv/administration"))
{
source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "FOUNDER", ci->GetName());
return;
@@ -240,7 +240,7 @@ class CommandEntryMessage : public Command
"\n"
"The \002{0} CLEAR\002 command clears the entry message list.\n"
"\n"
- "Use of this command requires being the founder of \037channel\037."),
+ "Use of this command requires the \002SET\002 privilege on \037channel\037."),
source.command);
return true;
}
diff --git a/modules/commands/cs_kick.cpp b/modules/commands/cs_kick.cpp
index 679ccfe06..89536df7f 100644
--- a/modules/commands/cs_kick.cpp
+++ b/modules/commands/cs_kick.cpp
@@ -50,6 +50,9 @@ class CommandCSKick : public Command
ChanServ::AccessGroup u_access = source.AccessFor(ci);
+ Anope::string signkickformat = Config->GetModule("chanserv")->Get<Anope::string>("signkickformat", "%m (%n)");
+ signkickformat = signkickformat.replace_all_cs("%n", source.GetNick());
+
if (!u_access.HasPriv("KICK") && !source.HasPriv("chanserv/kick"))
{
source.Reply(_("Access denied. You do not have privilege \002{0}\002 on \002{1}\002."), "KICK", ci->GetName());
@@ -71,14 +74,19 @@ class CommandCSKick : public Command
Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << u2->nick;
if (ci->HasFieldS("SIGNKICK") || (ci->HasFieldS("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;)
@@ -86,7 +94,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;
@@ -97,17 +106,22 @@ class CommandCSKick : public Command
continue;
++kicked;
+
if (ci->HasFieldS("SIGNKICK") || (ci->HasFieldS("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 \002{0}/{1}\002 users matching \002{2}\002 from \002{3}\002."), kicked, matched, target, c->name);
+ source.Reply(_("Kicked \002{0}/{1}\002 users matching \002{2}\002 from \002{3}\002."), kicked, matched, mask, c->name);
else
- source.Reply(_("No users on\002{0}\002 match \002{1}\002."), c->name, target);
+ source.Reply(_("No users on\002{0}\002 match \002{1}\002."), c->name, mask);
}
else
source.Reply(_("\002{0}\002 isn't currently in use."), target);
diff --git a/modules/commands/cs_mode.cpp b/modules/commands/cs_mode.cpp
index 67d1e5faa..121179a58 100644
--- a/modules/commands/cs_mode.cpp
+++ b/modules/commands/cs_mode.cpp
@@ -479,7 +479,7 @@ class CommandCSMode : public Command
case '*':
if (adding == -1 || !has_access)
break;
- for (unsigned j = 0; j < ModeManager::GetChannelModes().size(); ++j)
+ for (unsigned j = 0; j < ModeManager::GetChannelModes().size() && ci->c; ++j)
{
ChannelMode *cm = ModeManager::GetChannelModes()[j];
@@ -912,7 +912,7 @@ class CSMode : public Module
}
else if (cm->type == MODE_PARAM)
{
- /* If the channel doesnt have the mode, or it does and it isn't set correctly */
+ /* If the channel doesn't have the mode, or it does and it isn't set correctly */
if (ml->GetSet())
{
Anope::string param;
@@ -947,16 +947,40 @@ class CSMode : public Module
for (unsigned i = 0; i < mlock.length(); ++i)
{
if (mlock[i] == '+')
+ {
add = true;
- else if (mlock[i] == '-')
+ continue;
+ }
+
+ if (mlock[i] == '-')
+ {
add = false;
- else
+ continue;
+ }
+
+ ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock[i]);
+ if (!cm)
+ continue;
+
+ Anope::string param;
+ if (cm->type == MODE_PARAM)
{
- ChannelMode *cm = ModeManager::FindChannelModeByChar(mlock[i]);
- Anope::string param;
- if (cm && (cm->type == MODE_REGULAR || sep.GetToken(param)))
- mlocks->SetMLock(ci, cm, add, param);
+ ChannelModeParam *cmp = anope_dynamic_static_cast<ChannelModeParam *>(cm);
+ if (add || !cmp->minus_no_arg)
+ {
+ sep.GetToken(param);
+ if (param.empty() || !cmp->IsValid(param))
+ continue;
+ }
}
+ else if (cm->type != MODE_REGULAR)
+ {
+ sep.GetToken(param);
+ if (param.empty())
+ continue;
+ }
+
+ mlocks->SetMLock(ci, cm, add, param);
}
}
}
diff --git a/modules/commands/cs_set.cpp b/modules/commands/cs_set.cpp
index f7ee80050..06c996f52 100644
--- a/modules/commands/cs_set.cpp
+++ b/modules/commands/cs_set.cpp
@@ -850,7 +850,7 @@ class CommandCSSetSecureOps : public Command
bool OnHelp(CommandSource &source, const Anope::string &) override
{
source.Reply(_("Enables or disables the \002secure ops\002 option for \037channel\037."
- " When \002secure ops\002 is set, users will not be allowed to have channel operator status if they do not have the privileges to have it."));
+ " When \002secure ops\002 is set, users will not be allowed to have channel operator status if they do not have the privileges for it."));
return true;
}
};
@@ -1066,13 +1066,11 @@ class CommandCSSetNoexpire : public Command
class CSSet : public Module
, public EventHook<Event::CreateChan>
- , public EventHook<Event::ChannelCreate>
, public EventHook<Event::ChannelSync>
, public EventHook<Event::CheckKick>
, public EventHook<Event::DelChan>
, public EventHook<Event::ChannelModeSet>
, public EventHook<Event::ChannelModeUnset>
- , public EventHook<Event::CheckDelete>
, public EventHook<Event::JoinChannel>
, public EventHook<Event::SetCorrectModes>
, public EventHook<ChanServ::Event::PreChanExpire>
@@ -1097,6 +1095,8 @@ class CSSet : public Module
CommandCSSetSuccessor commandcssetsuccessor;
CommandCSSetNoexpire commandcssetnoexpire;
+ ExtensibleRef<bool> inhabit;
+
bool persist_lower_ts;
public:
@@ -1129,6 +1129,8 @@ class CSSet : public Module
, commandcssetsignkick(this)
, commandcssetsuccessor(this)
, commandcssetnoexpire(this)
+
+ , inhabit("inhabit")
{
}
@@ -1142,18 +1144,13 @@ class CSSet : public Module
ci->SetBanType(Config->GetModule(this)->Get<int>("defbantype", "2"));
}
- void OnChannelCreate(Channel *c) override
+ void OnChannelSync(Channel *c) override
{
if (c->ci && keep_modes.HasExt(c->ci))
for (ChanServ::Mode *m : c->ci->GetRefs<ChanServ::Mode *>(ChanServ::mode))
c->SetMode(c->ci->WhoSends(), m->GetMode(), m->GetParam());
}
- void OnChannelSync(Channel *c) override
- {
- OnChannelCreate(c);
- }
-
EventReturn OnCheckKick(User *u, Channel *c, Anope::string &mask, Anope::string &reason) override
{
if (!c->ci || !restricted.HasExt(c->ci) || c->MatchesList(u, "EXCEPT"))
@@ -1180,7 +1177,7 @@ class CSSet : public Module
if (mode->name == "PERM")
persist.Set(c->ci, true);
- if (mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && ChanServ::mode)
+ if (mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && ChanServ::mode && (!inhabit || !inhabit->HasExt(c)))
{
ChanServ::Mode *m = ChanServ::mode.Create();
m->SetChannel(c->ci);
@@ -1200,7 +1197,7 @@ class CSSet : public Module
persist.Unset(c->ci);
}
- if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced())
+ if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && (!inhabit || !inhabit->HasExt(c)))
for (ChanServ::Mode *m : c->ci->GetRefs<ChanServ::Mode *>(ChanServ::mode))
if (m->GetMode() == mode->name && m->GetParam().equals_ci(param))
m->Delete();
@@ -1208,13 +1205,6 @@ class CSSet : public Module
return EVENT_CONTINUE;
}
- EventReturn OnCheckDelete(Channel *c) override
- {
- if (c->ci && persist.HasExt(c->ci))
- return EVENT_STOP;
- return EVENT_CONTINUE;
- }
-
void OnJoinChannel(User *u, Channel *c) override
{
if (persist_lower_ts && c->ci && persist.HasExt(c->ci) && c->creation_time > c->ci->GetTimeRegistered())
diff --git a/modules/commands/cs_topic.cpp b/modules/commands/cs_topic.cpp
index 9e8b3764a..a132900a6 100644
--- a/modules/commands/cs_topic.cpp
+++ b/modules/commands/cs_topic.cpp
@@ -195,7 +195,7 @@ class CommandCSTopic : public Command
" The \002APPEND\002 command appends the given topic to the existing topic.\n"
"\n"
"\002LOCK\002 and \002UNLOCK\002 may be used to enable and disable topic lock."
- " When topic lock is set, the channel topic will be unchangeable except via this command.\n"
+ " When topic lock is set, the channel topic will be unchangeable by users who do not have the \002TOPIC\002 privilege.\n"
"\n"
"Use of this command requires the \002{0}\002 privilege on \037channel\037."),
"TOPIC");
@@ -235,7 +235,7 @@ class CSTopic : public Module
}
}
- void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) override
+ void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override
{
if (!c->ci)
return;
@@ -245,7 +245,7 @@ class CSTopic : public Module
* This desyncs what is really set with what we have stored, and we end up resetting the topic often when
* it is not required
*/
- if (topiclock.HasExt(c->ci) && c->ci->GetLastTopic() != c->topic)
+ if (topiclock.HasExt(c->ci) && c->ci->GetLastTopic() != c->topic && (!source || !c->ci->AccessFor(source).HasPriv("TOPIC")))
{
c->ChangeTopic(c->ci->GetLastTopicSetter(), c->ci->GetLastTopic(), c->ci->GetLastTopicTime());
}
diff --git a/modules/commands/hs_del.cpp b/modules/commands/hs_del.cpp
index 4d7e7aac9..b45c10a61 100644
--- a/modules/commands/hs_del.cpp
+++ b/modules/commands/hs_del.cpp
@@ -101,7 +101,8 @@ class HSDel : public Module
, commandhsdelall(this, ondeletevhost)
, ondeletevhost(this)
{
-
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
};
diff --git a/modules/commands/hs_group.cpp b/modules/commands/hs_group.cpp
index 8a7a208a6..c3971fdea 100644
--- a/modules/commands/hs_group.cpp
+++ b/modules/commands/hs_group.cpp
@@ -86,6 +86,8 @@ class HSGroup : public Module
HSGroup(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, commandhsgroup(this)
{
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
void OnSetVhost(NickServ::Nick *na) override
diff --git a/modules/commands/hs_list.cpp b/modules/commands/hs_list.cpp
index f363c81f7..738f9f1bd 100644
--- a/modules/commands/hs_list.cpp
+++ b/modules/commands/hs_list.cpp
@@ -151,6 +151,8 @@ class HSList : public Module
HSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, commandhslist(this)
{
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
};
diff --git a/modules/commands/hs_off.cpp b/modules/commands/hs_off.cpp
index 6f88de67e..8f3c7e3da 100644
--- a/modules/commands/hs_off.cpp
+++ b/modules/commands/hs_off.cpp
@@ -31,6 +31,7 @@ class CommandHSOff : public Command
return;
}
+ u->vhost.clear();
IRCD->SendVhostDel(u);
Log(LOG_COMMAND, source, this) << "to disable their vhost";
source.Reply(_("Your vhost was removed and the normal cloaking restored."));
@@ -51,7 +52,8 @@ class HSOff : public Module
HSOff(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, commandhsoff(this)
{
-
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
};
diff --git a/modules/commands/hs_on.cpp b/modules/commands/hs_on.cpp
index dcc134eef..409d56ac5 100644
--- a/modules/commands/hs_on.cpp
+++ b/modules/commands/hs_on.cpp
@@ -62,7 +62,8 @@ class HSOn : public Module
HSOn(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
, commandhson(this)
{
-
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
};
diff --git a/modules/commands/hs_set.cpp b/modules/commands/hs_set.cpp
index 33fa39950..a86afead4 100644
--- a/modules/commands/hs_set.cpp
+++ b/modules/commands/hs_set.cpp
@@ -208,7 +208,8 @@ class HSSet : public Module
, commandhsset(this)
, commandhssetall(this)
{
-
+ if (!IRCD || !IRCD->CanSetVHost)
+ throw ModuleException("Your IRCd does not support vhosts");
}
};
diff --git a/modules/commands/ms_read.cpp b/modules/commands/ms_read.cpp
index 9af997789..687843124 100644
--- a/modules/commands/ms_read.cpp
+++ b/modules/commands/ms_read.cpp
@@ -29,14 +29,14 @@ static void rsend_notify(CommandSource &source, MemoServ::MemoInfo *mi, MemoServ
if (!nc)
return;
- /* Text of the memo varies if the recepient was a
+ /* Text of the memo varies if the recipient was a
nick or channel */
Anope::string text = Anope::printf(Language::Translate(na->GetAccount(), _("\002[auto-memo]\002 The memo you sent to \002%s\002 has been viewed.")), targ.c_str());
/* Send notification */
MemoServ::service->Send(source.GetNick(), m->GetSender(), text, true);
- /* Notify recepient of the memo that a notification has
+ /* Notify recipient of the memo that a notification has
been sent to the sender */
source.Reply(_("A notification memo has been sent to \002{0}\002 informing him/her you have read his/her memo."), nc->GetDisplay());
}
diff --git a/modules/commands/ms_set.cpp b/modules/commands/ms_set.cpp
index 94e7f2e26..c924d0ea0 100644
--- a/modules/commands/ms_set.cpp
+++ b/modules/commands/ms_set.cpp
@@ -254,7 +254,7 @@ class CommandMSSet : public Command
" NEW You will only be notified of memos when they\n"
" are sent to you.\n"
"\n"
- " MAIL You will be notified of memos by email aswell as\n"
+ " MAIL You will be notified of memos by email as well as\n"
" any other settings you have.\n"
"\n"
" NOMAIL You will not be notified of memos by email.\n"
diff --git a/modules/commands/ns_alist.cpp b/modules/commands/ns_alist.cpp
index 01a0419b7..e4aaff38b 100644
--- a/modules/commands/ns_alist.cpp
+++ b/modules/commands/ns_alist.cpp
@@ -75,7 +75,7 @@ class CommandNSAList : public Command
continue;
}
- ChanServ::AccessGroup access = ci->AccessFor(nc);
+ ChanServ::AccessGroup access = ci->AccessFor(nc, false);
if (access.empty())
continue;
diff --git a/modules/commands/ns_identify.cpp b/modules/commands/ns_identify.cpp
index 2a2b468bf..122378d8a 100644
--- a/modules/commands/ns_identify.cpp
+++ b/modules/commands/ns_identify.cpp
@@ -89,8 +89,16 @@ class CommandNSIdentify : public Command
return;
}
+ unsigned int maxlogins = Config->GetModule(this->owner)->Get<unsigned int>("maxlogins");
+ if (na && maxlogins && na->GetAccount()->users.size() >= maxlogins)
+ {
+ source.Reply(_("Account \002{0}\002 has already reached the maximum number of simultaneous logins ({1})."), na->GetAccount()->GetDisplay(), maxlogins);
+ return;
+ }
+
NickServ::IdentifyRequest *req = NickServ::service->CreateIdentifyRequest(new NSIdentifyRequestListener(source, this), owner, na ? na->GetAccount()->GetDisplay() : nick, pass);
Event::OnCheckAuthentication(&Event::CheckAuthentication::OnCheckAuthentication, u, req);
+
req->Dispatch();
}
diff --git a/modules/commands/ns_logout.cpp b/modules/commands/ns_logout.cpp
index f63086789..9bcb543fc 100644
--- a/modules/commands/ns_logout.cpp
+++ b/modules/commands/ns_logout.cpp
@@ -46,8 +46,10 @@ class CommandNSLogout : public Command
return;
}
+#if 0
if (!nick.empty() && !param.empty() && param.equals_ci("REVALIDATE") && NickServ::service)
NickServ::service->Validate(u2);
+#endif
u2->super_admin = false; /* Dont let people logout and remain a SuperAdmin */
Log(LOG_COMMAND, source, this) << "to logout " << u2->nick;
diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp
index 5d52feda4..c7e6e5af2 100644
--- a/modules/commands/ns_register.cpp
+++ b/modules/commands/ns_register.cpp
@@ -155,6 +155,12 @@ class CommandNSRegister : public Command
return;
}
+ if (ServiceBot::Find(u_nick, true))
+ {
+ source.Reply(_("\002{0}\002 may not be registered."), u_nick);
+ return;
+ }
+
if (Config->GetModule("nickserv")->Get<bool>("restrictopernicks"))
for (Oper *o : Serialize::GetObjects<Oper *>(operblock))
{
@@ -165,6 +171,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, "");
diff --git a/modules/commands/ns_set.cpp b/modules/commands/ns_set.cpp
index 9f1e16778..a75386743 100644
--- a/modules/commands/ns_set.cpp
+++ b/modules/commands/ns_set.cpp
@@ -404,10 +404,12 @@ class CommandNSSetEmail : public Command
message = Config->GetBlock("mail")->Get<Anope::string>("emailchange_message");
subject = subject.replace_all_cs("%e", u->Account()->GetEmail());
+ subject = subject.replace_all_cs("%E", new_email);
subject = subject.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<Anope::string>("networkname"));
subject = subject.replace_all_cs("%c", code);
message = message.replace_all_cs("%e", u->Account()->GetEmail());
+ message = message.replace_all_cs("%E", new_email);
message = message.replace_all_cs("%N", Config->GetBlock("networkinfo")->Get<Anope::string>("networkname"));
message = message.replace_all_cs("%c", code);
diff --git a/modules/commands/os_mode.cpp b/modules/commands/os_mode.cpp
index d4551e69f..30e1d502b 100644
--- a/modules/commands/os_mode.cpp
+++ b/modules/commands/os_mode.cpp
@@ -26,7 +26,7 @@ class CommandOSMode : public Command
const Anope::string &target = params[0];
const Anope::string &modes = params[1];
- Channel *c = Channel::Find(target);
+ Reference<Channel> c = Channel::Find(target);
if (!c)
source.Reply(_("Channel \002{0}\002 doesn't exist."), target);
else if (c->bouncy_modes)
@@ -36,9 +36,15 @@ class CommandOSMode : public Command
bool all = params.size() > 2 && params[2].equals_ci("ALL");
const Channel::ModeList chmodes = c->GetModes();
- for (Channel::ModeList::const_iterator it = chmodes.begin(), it_end = chmodes.end(); it != it_end; ++it)
+ for (Channel::ModeList::const_iterator it = chmodes.begin(), it_end = chmodes.end(); it != it_end && c; ++it)
c->RemoveMode(c->ci->WhoSends(), it->first, it->second, false);
+ if (!c)
+ {
+ source.Reply(_("Modes cleared on %s and the channel destroyed."), target.c_str());
+ return;
+ }
+
if (all)
{
for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ++it)
@@ -65,7 +71,7 @@ class CommandOSMode : public Command
Anope::string log_modes, log_params;
sep.GetToken(mode);
- for (unsigned i = 0; i < mode.length(); ++i)
+ for (unsigned i = 0; i < mode.length() && c; ++i)
{
char ch = mode[i];
@@ -116,7 +122,7 @@ class CommandOSMode : public Command
}
if (!log_modes.replace_all_cs("+", "").replace_all_cs("-", "").empty())
- Log(LOG_ADMIN, source, this) << log_modes << log_params << " on " << c->name;
+ Log(LOG_ADMIN, source, this) << log_modes << log_params << " on " << (c ? c->name : target);
}
}
diff --git a/modules/database/db_flatfile.cpp b/modules/database/db_flatfile.cpp
index 2486a2307..122134960 100644
--- a/modules/database/db_flatfile.cpp
+++ b/modules/database/db_flatfile.cpp
@@ -57,7 +57,7 @@ class DBFlatFile : public Module
Anope::string err = Anope::LastError();
Log(this) << "Unable to back up database " << *it << " (" << err << ")!";
- if (!Config->GetModule(this)->Get<bool>("nobackupok"))
+ if (!Config->GetModule(this)->Get<bool>("nobackupokay"))
{
Anope::Quitting = true;
Anope::QuitReason = "Unable to back up database " + *it + " (" + err + ")";
diff --git a/modules/database/db_old.cpp b/modules/database/db_old.cpp
index dff08250e..3d9b92922 100644
--- a/modules/database/db_old.cpp
+++ b/modules/database/db_old.cpp
@@ -723,7 +723,7 @@ static void LoadVHosts()
NickServ::Nick *na = NickServ::FindNick(nick);
if (na == NULL)
{
- Log() << "Removing vhost for nonexistant nick " << nick;
+ Log() << "Removing vhost for non-existent nick " << nick;
continue;
}
diff --git a/modules/extra/m_ldap.cpp b/modules/extra/m_ldap.cpp
index 8309a5cc5..71c31b9ac 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,21 +16,136 @@
#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;
- int port;
Anope::string admin_binddn;
Anope::string admin_pass;
- time_t timeout;
LDAP *con;
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 +172,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,26 +184,8 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
delete [] mods;
}
- void Reconnect()
- {
- /* Only try one connect a minute. It is an expensive blocking operation */
- if (last_connect > Anope::CurTime - 60)
- throw LDAPException("Unable to connect to LDAP service " + this->name + ": reconnecting too fast");
- last_connect = Anope::CurTime;
-
- ldap_unbind_ext(this->con, NULL, NULL);
- int i = ldap_initialize(&this->con, this->server.c_str());
- if (i != LDAP_SUCCESS)
- throw LDAPException("Unable to connect to LDAP service " + this->name + ": " + ldap_err2string(i));
- }
-
- 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;
-
- 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)
+ private:
+ void Connect()
{
int i = ldap_initialize(&this->con, this->server.c_str());
if (i != LDAP_SUCCESS)
@@ -94,366 +202,243 @@ class LDAPService : public LDAPProvider, public Thread, public Condition
throw LDAPException("Unable to set timeout for " + this->name + ": " + ldap_err2string(i));
}
+ void Reconnect()
+ {
+ /* Only try one connect a minute. It is an expensive blocking operation */
+ if (last_connect > Anope::CurTime - 60)
+ throw LDAPException("Unable to connect to LDAP service " + this->name + ": reconnecting too fast");
+ last_connect = Anope::CurTime;
+
+ ldap_unbind_ext(this->con, NULL, NULL);
+
+ Connect();
+ }
+
+ void QueueRequest(LDAPRequest *r)
+ {
+ this->Lock();
+ this->queries.push_back(r);
+ this->Wakeup();
+ this->Unlock();
+ }
+
+ public:
+ 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, const Anope::string &b, const Anope::string &p) : LDAPProvider(o, n), server(s), admin_binddn(b), admin_pass(p), last_connect(0)
+ {
+ Connect();
+ }
+
~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];
+
+ /* 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);
- ldap_abandon_ext(this->con, msgid, NULL, NULL);
- if (i)
- i->OnDelete();
+ 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) 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) override
+ void Bind(LDAPInterface *i, const Anope::string &who, const Anope::string &pass) 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) override
+ void Search(LDAPInterface *i, const Anope::string &base, const Anope::string &filter) 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) override
+ void Add(LDAPInterface *i, const Anope::string &dn, LDAPMods &attributes) 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) 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) 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() 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);
-
- this->Lock();
+ process_mutex.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)
- {
- attributes["dn"].push_back(dn);
- ldap_memfree(dn);
- dn = NULL;
- }
-
- switch (cur_type)
+ /* try again */
+ try
{
- 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;
+ Reconnect();
}
-
- switch (cur_type)
+ catch (const LDAPException &)
{
- 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();
+ results.push_back(req);
+ this->Unlock();
+ }
+
+ me->Notify();
+
+ process_mutex.Unlock();
+ }
+ public:
+ void Run() anope_override
+ {
+ while (!this->GetExitState())
+ {
this->Lock();
- this->results.push_back(std::make_pair(i, ldap_result));
+ /* 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
, public EventHook<Event::ModuleUnload>
{
std::map<Anope::string, LDAPService *> LDAPServices;
+
public:
ModuleLDAP(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
{
me = this;
-
}
~ModuleLDAP()
@@ -490,6 +475,8 @@ class ModuleLDAP : public Module, public Pipe
s->SetExitState();
s->Wakeup();
+ s->Join();
+ delete s;
this->LDAPServices.erase(cname);
}
}
@@ -503,14 +490,12 @@ class ModuleLDAP : public Module, public Pipe
if (this->LDAPServices.find(connname) == this->LDAPServices.end())
{
const Anope::string &server = ldap->Get<Anope::string>("server", "127.0.0.1");
- int port = ldap->Get<int>("port", "389");
const Anope::string &admin_binddn = ldap->Get<Anope::string>("admin_binddn");
- const Anope::string &admin_password = ldap->Get<Anope::string>("admin_password");
- time_t timeout = ldap->Get<time_t>("timeout", "5");
+ const Anope::string &admin_password = ldap->GetAnope::string>("admin_password");
try
{
- LDAPService *ss = new LDAPService(this, connname, server, port, admin_binddn, admin_password, timeout);
+ LDAPService *ss = new LDAPService(this, connname, server, admin_binddn, admin_password);
ss->Start();
this->LDAPServices.insert(std::make_pair(connname, ss));
@@ -529,31 +514,35 @@ 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();
}
}
@@ -563,15 +552,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)
{
@@ -584,11 +574,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 f5b03a606..dd63fd3fb 100644
--- a/modules/extra/m_ldap_authentication.cpp
+++ b/modules/extra/m_ldap_authentication.cpp
@@ -31,36 +31,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) 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) override
+ {
if (!ii->lprov)
- {
- delete ii;
return;
- }
switch (r.type)
{
- case LDAPResult::QUERY_SEARCH:
+ case QUERY_SEARCH:
{
if (!r.empty())
{
@@ -69,9 +62,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)
{
@@ -80,7 +73,7 @@ class IdentifyInterface : public LDAPInterface
}
break;
}
- case LDAPResult::QUERY_BIND:
+ case QUERY_BIND:
{
if (ii->admin_bind)
{
@@ -88,10 +81,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)
{
@@ -121,40 +113,28 @@ class IdentifyInterface : public LDAPInterface
default:
break;
}
-
- delete ii;
}
void OnError(const LDAPResult &r) 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) 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;
@@ -181,7 +161,6 @@ class OnIdentifyInterface : public LDAPInterface
void OnError(const LDAPResult &r) override
{
- this->requests.erase(r.id);
Log(this->owner) << r.error;
}
};
@@ -202,15 +181,13 @@ class OnRegisterInterface : public LDAPInterface
}
};
-class NSIdentifyLDAP : public Module
+class ModuleLDAPAuthentication : public Module
, public EventHook<Event::PreCommand>
, public EventHook<Event::CheckAuthentication>
, public EventHook<Event::NickIdentify>
, public EventHook<NickServ::Event::NickRegister>
{
ServiceReference<LDAPProvider> ldap;
- IdentifyInterface iinterface;
- OnIdentifyInterface oninterface;
OnRegisterInterface orinterface;
PrimitiveExtensibleItem<Anope::string> dn;
@@ -218,29 +195,18 @@ class NSIdentifyLDAP : public Module
Anope::string password_attribute;
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)
+ public:
+ ModuleLDAPAuthentication(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
, EventHook<Event::PreCommand>("OnPreCommand", EventHook<Event::PreCommand>::Priority::FIRST)
, EventHook<Event::CheckAuthentication>("OnCheckAuthentication", EventHook<Event::CheckAuthentication>::Priority::FIRST)
, EventHook<Event::NickIdentify>("OnNickIdentify", EventHook<Event::NickIdentify>::Priority::FIRST)
, EventHook<NickServ::Event::NickRegister>("OnNickRegister", EventHook<NickServ::Event::NickRegister>::Priority::FIRST)
, ldap("LDAPProvider", "ldap/main")
- , iinterface(this)
- , oninterface(this)
, orinterface(this)
, dn(this, "m_ldap_authentication_dn")
{
-
me = this;
-<<<<<<< HEAD
-=======
- }
-
- void Prioritize() anope_override
- {
- ModuleManager::SetPriority(this, PRIORITY_FIRST);
->>>>>>> 2.0
}
void OnReload(Configuration::Conf *config) override
@@ -287,16 +253,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) override
@@ -308,57 +265,38 @@ 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 + "=*)");
}
-<<<<<<< HEAD
- void OnNickRegister(User *, NickServ::Nick *na) override
-=======
- void OnNickRegister(User *, NickAlias *na, const Anope::string &pass) anope_override
->>>>>>> 2.0
+ void OnNickRegister(User *, NickServ::Nick *na, const Anope::string &pass) override
{
if (!this->disable_register_reason.empty() || !this->ldap)
return;
- try
- {
- this->ldap->BindAsAdmin(NULL);
-
- LDAPMods attributes;
- attributes.resize(4);
+ this->ldap->BindAsAdmin(NULL);
- attributes[0].name = "objectClass";
- attributes[0].values.push_back("top");
- attributes[0].values.push_back(object_class);
+ LDAPMods attributes;
+ attributes.resize(4);
- attributes[1].name = username_attribute;
- attributes[1].values.push_back(na->GetNick());
-
- if (!na->GetAccount()->GetEmail().empty())
- {
- attributes[2].name = email_attribute;
- attributes[2].values.push_back(na->GetAccount()->GetEmail());
- }
+ 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->GetNick());
- Anope::string new_dn = username_attribute + "=" + na->GetNick() + "," + basedn;
- this->ldap->Add(&this->orinterface, new_dn, attributes);
- }
- catch (const LDAPException &ex)
+ if (!na->GetAccount()->GetEmail().empty())
{
- Log(this) << ex.GetReason();
+ attributes[2].name = email_attribute;
+ attributes[2].values.push_back(na->GetAccount()->GetEmail());
}
+
+ attributes[3].name = this->password_attribute;
+ attributes[3].values.push_back(pass);
+
+ Anope::string new_dn = username_attribute + "=" + na->GetNick() + "," + basedn;
+ this->ldap->Add(&this->orinterface, new_dn, attributes);
}
};
-MODULE_INIT(NSIdentifyLDAP)
+MODULE_INIT(ModuleLDAPAuthentication)
diff --git a/modules/extra/m_ldap_oper.cpp b/modules/extra/m_ldap_oper.cpp
index 221e16f98..31653544e 100644
--- a/modules/extra/m_ldap_oper.cpp
+++ b/modules/extra/m_ldap_oper.cpp
@@ -6,27 +6,15 @@ static Anope::string opertype_attribute;
class IdentifyInterface : public LDAPInterface
{
- std::map<LDAPQuery, Anope::string> requests;
+ Reference<User> u;
public:
- IdentifyInterface(Module *m) : LDAPInterface(m)
+ IdentifyInterface(Module *m, User *user) : LDAPInterface(m), u(user)
{
}
- void Add(LDAPQuery id, const Anope::string &nick)
- {
- this->requests[id] = nick;
- }
-
void OnResult(const LDAPResult &r) 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);
-
-
if (!u || !u->Account())
return;
@@ -50,11 +38,8 @@ class IdentifyInterface : public LDAPInterface
o = new Oper(u->nick, ot);
my_opers.insert(o);
nc->o = o;
-<<<<<<< HEAD
- Log(this->owner) << "m_ldap_oper: Tied " << u->nick << " (" << nc->GetDisplay() << ") to opertype " << ot->GetName();
-=======
- Log(this->owner) << "Tied " << u->nick << " (" << nc->display << ") to opertype " << ot->GetName();
->>>>>>> 2.0
+
+ Log(this->owner) << "Tied " << u->nick << " (" << nc->GetDisplay() << ") to opertype " << ot->GetName();
}
}
catch (const LDAPException &ex)
@@ -68,18 +53,18 @@ class IdentifyInterface : public LDAPInterface
}
nc->o = NULL;
-<<<<<<< HEAD
- Log() << "Removed services operator from " << u->nick << " (" << nc->GetDisplay() << ")";
-=======
- Log(this->owner) << "Removed services operator from " << u->nick << " (" << nc->display << ")";
->>>>>>> 2.0
+ Log(this->owner) << "Removed services operator from " << u->nick << " (" << nc->GetDisplay() << ")";
}
}
}
void OnError(const LDAPResult &r) override
{
- this->requests.erase(r.id);
+ }
+
+ void OnDelete() anope_override
+ {
+ delete this;
}
};
@@ -88,16 +73,15 @@ class LDAPOper : public Module
, public EventHook<Event::DelCore>
{
ServiceReference<LDAPProvider> ldap;
- IdentifyInterface iinterface;
Anope::string binddn;
Anope::string password;
Anope::string basedn;
Anope::string filter;
public:
- LDAPOper(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
+ LDAPOper(const Anope::string &modname, const Anope::string &creator)
+ : Module(modname, creator, EXTRA | VENDOR)
, ldap("LDAPProvider", "ldap/main")
- , iinterface(this)
{
}
@@ -128,8 +112,7 @@ class LDAPOper : public Module
if (!this->binddn.empty())
this->ldap->Bind(NULL, this->binddn.replace_all_cs("%a", u->Account()->GetDisplay()), this->password.c_str());
- LDAPQuery id = this->ldap->Search(&this->iinterface, this->basedn, this->filter.replace_all_cs("%a", u->Account()->GetDisplay()));
- this->iinterface.Add(id, u->nick);
+ this->ldap->Search(new IdentifyInterface(this, u), this->basedn, this->filter.replace_all_cs("%a", u->Account()->GetDisplay()));
}
catch (const LDAPException &ex)
{
diff --git a/modules/extra/m_ssl_openssl.cpp b/modules/extra/m_ssl_openssl.cpp
index 748f467cf..c5e2feefc 100644
--- a/modules/extra/m_ssl_openssl.cpp
+++ b/modules/extra/m_ssl_openssl.cpp
@@ -105,6 +105,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);
@@ -160,6 +164,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() override
diff --git a/modules/extra/stats/irc2sql/irc2sql.cpp b/modules/extra/stats/irc2sql/irc2sql.cpp
index fbb56f4a7..e0c03edbd 100644
--- a/modules/extra/stats/irc2sql/irc2sql.cpp
+++ b/modules/extra/stats/irc2sql/irc2sql.cpp
@@ -131,6 +131,15 @@ void IRC2SQL::OnUserNickChange(User *u, const Anope::string &oldnick)
this->RunQuery(query);
}
+void IRC2SQL::OnUserAway(User *u, const Anope::string &message)
+{
+ query = "UPDATE `" + prefix + "user` SET away=@away@, awaymsg=@awaymsg@ WHERE nick=@nick@";
+ query.SetValue("away", (!message.empty()) ? "Y" : "N");
+ query.SetValue("awaymsg", message);
+ query.SetValue("nick", u->nick);
+ this->RunQuery(query);
+}
+
void IRC2SQL::OnFingerprint(User *u)
{
query = "UPDATE `" + prefix + "user` SET secure=@secure@, fingerprint=@fingerprint@ WHERE nick=@nick@";
@@ -243,7 +252,7 @@ void IRC2SQL::OnLeaveChannel(User *u, Channel *c)
this->RunQuery(query);
}
-void IRC2SQL::OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic)
+void IRC2SQL::OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic)
{
query = "UPDATE `" + prefix + "chan` "
"SET topic=@topic@, topicauthor=@author@, topictime=FROM_UNIXTIME(@time@) "
diff --git a/modules/extra/stats/irc2sql/irc2sql.h b/modules/extra/stats/irc2sql/irc2sql.h
index 175e37681..b73e95cf1 100644
--- a/modules/extra/stats/irc2sql/irc2sql.h
+++ b/modules/extra/stats/irc2sql/irc2sql.h
@@ -55,6 +55,7 @@ class IRC2SQL : public Module
void OnUserConnect(User *u, bool &exempt) override;
void OnUserQuit(User *u, const Anope::string &msg) override;
void OnUserNickChange(User *u, const Anope::string &oldnick) override;
+ void OnUserAway(User *u, const Anope::string &message) override;
void OnFingerprint(User *u) override;
void OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname) override;
void OnUserModeUnset(const MessageSource &setter, User *u, const Anope::string &mname) override;
@@ -69,7 +70,7 @@ class IRC2SQL : public Module
EventReturn OnChannelModeSet(Channel *c, const MessageSource &setter, ChannelMode *mode, const Anope::string &param) override;
EventReturn OnChannelModeUnset(Channel *c, const MessageSource &setter, ChannelMode *mode, const Anope::string &param) override;
- void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) override;
+ void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override;
void OnBotNotice(User *u, ServiceBot *bi, Anope::string &message) override;
};
diff --git a/modules/extra/stats/m_chanstats.cpp b/modules/extra/stats/m_chanstats.cpp
index 0278f7805..687c077b5 100644
--- a/modules/extra/stats/m_chanstats.cpp
+++ b/modules/extra/stats/m_chanstats.cpp
@@ -424,7 +424,7 @@ class MChanstats : public Module
"END;";
this->RunQuery(query);
- /* dont prepend any database prefix to events so we can always delete/change old events */
+ /* don't prepend any database prefix to events so we can always delete/change old events */
if (this->HasEvent("chanstats_event_cleanup_daily"))
{
query = "DROP EVENT chanstats_event_cleanup_daily";
@@ -517,14 +517,13 @@ class MChanstats : public Module
info.AddOption(_("Chanstats"));
}
- void OnTopicUpdated(Channel *c, const Anope::string &user, const Anope::string &topic) override
+ void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override
{
- User *u = User::Find(user);
- if (!u || !u->Account() || !c->ci || !cs_stats.HasExt(c->ci))
+ if (!source || !source->Account() || !c->ci || !cs_stats.HasExt(c->ci))
return;
query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);";
query.SetValue("channel", c->name);
- query.SetValue("nick", GetDisplay(u));
+ query.SetValue("nick", GetDisplay(source));
this->RunQuery(query);
}
diff --git a/modules/fantasy.cpp b/modules/fantasy.cpp
index 53cc03e17..3781b5b83 100644
--- a/modules/fantasy.cpp
+++ b/modules/fantasy.cpp
@@ -113,13 +113,29 @@ class Fantasy : public Module
std::vector<Anope::string> params;
spacesepstream(msg).GetTokens(params);
- if (!msg.find(c->ci->GetBot()->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->GetBot()->nick))
+ {
params.erase(params.begin());
- else if (!msg.find_first_of(Config->GetModule(this)->Get<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;
@@ -133,7 +149,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())
@@ -143,7 +159,7 @@ class Fantasy : public Module
ServiceReference<Command> cmd("Command", info.name);
if (!cmd)
{
- Log(LOG_DEBUG) << "Fantasy command " << it->first << " exists for nonexistant service " << info.name << "!";
+ Log(LOG_DEBUG) << "Fantasy command " << it->first << " exists for non-existent service " << info.name << "!";
return;
}
diff --git a/modules/m_dns.cpp b/modules/m_dns.cpp
index c5fe8a767..1ea70a6ed 100644
--- a/modules/m_dns.cpp
+++ b/modules/m_dns.cpp
@@ -22,10 +22,15 @@ namespace
time_t timeout;
}
-/** A full packet sent or recieved to/from the nameserver
+/** A full packet sent or received to/from the nameserver
*/
class Packet : public Query
{
+ static bool IsValidName(const Anope::string &name)
+ {
+ return name.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-") == Anope::string::npos;
+ }
+
void PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name)
{
if (pos + name.length() + 2 > output_size)
@@ -116,6 +121,9 @@ class Packet : public Query
if (pos + 4 > input_size)
throw SocketException("Unable to unpack question");
+ if (!IsValidName(question.name))
+ throw SocketException("Invalid question name");
+
question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]);
pos += 2;
@@ -179,6 +187,10 @@ class Packet : public Query
case QUERY_PTR:
{
record.rdata = this->UnpackName(input, input_size, pos);
+
+ if (!IsValidName(record.rdata))
+ throw SocketException("Invalid cname/ptr record data");
+
break;
}
default:
@@ -792,7 +804,7 @@ class MyManager : public Manager, public Timer
}
Packet *packet = new Packet(recv_packet);
- packet->flags |= QUERYFLAGS_QR; /* This is a reponse */
+ packet->flags |= QUERYFLAGS_QR; /* This is a response */
packet->flags |= QUERYFLAGS_AA; /* And we are authoritative */
packet->answers.clear();
diff --git a/modules/m_xmlrpc.cpp b/modules/m_xmlrpc.cpp
index 3830b2ac8..2d1cd2c0e 100644
--- a/modules/m_xmlrpc.cpp
+++ b/modules/m_xmlrpc.cpp
@@ -53,6 +53,39 @@ class MyXMLRPCServiceInterface : public XMLRPCServiceInterface, public HTTPPage
return ret;
}
+ static Anope::string Unescape(const Anope::string &string)
+ {
+ Anope::string ret = string;
+ for (int i = 0; special[i].character.empty() == false; ++i)
+ if (!special[i].replace.empty())
+ ret = ret.replace_all_cs(special[i].replace, special[i].character);
+
+ for (size_t i, last = 0; (i = string.find("&#", last)) != Anope::string::npos;)
+ {
+ last = i + 1;
+
+ size_t end = string.find(';', i);
+ if (end == Anope::string::npos)
+ break;
+
+ Anope::string ch = string.substr(i + 2, end - (i + 2));
+
+ if (ch.empty())
+ continue;
+
+ long l;
+ if (!ch.empty() && ch[0] == 'x')
+ l = strtol(ch.substr(1).c_str(), NULL, 16);
+ else
+ l = strtol(ch.c_str(), NULL, 10);
+
+ if (l > 0 && l < 256)
+ ret = ret.replace_all_cs("&#" + ch + ";", Anope::string(l));
+ }
+
+ return ret;
+ }
+
private:
static bool GetData(Anope::string &content, Anope::string &tag, Anope::string &data)
{
@@ -98,8 +131,8 @@ class MyXMLRPCServiceInterface : public XMLRPCServiceInterface, public HTTPPage
}
while (istag && !content.empty());
- tag = prev;
- data = cur;
+ tag = Unescape(prev);
+ data = Unescape(cur);
return !istag && !data.empty();
}
@@ -146,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<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);
}
@@ -162,12 +195,8 @@ class ModuleXMLRPC : public Module
MyXMLRPCServiceInterface xmlrpcinterface;
ModuleXMLRPC(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR)
- , httpref("HTTPProvider", "httpd/main")
, xmlrpcinterface(this, "xmlrpc")
{
- if (!httpref)
- throw ModuleException("Unable to find http reference, is m_httpd loaded?");
- httpref->RegisterPage(&xmlrpcinterface);
}
@@ -179,7 +208,12 @@ class ModuleXMLRPC : public Module
void OnReload(Configuration::Conf *conf) override
{
+ if (httpref)
+ httpref->UnregisterPage(&xmlrpcinterface);
this->httpref = ServiceReference<HTTPProvider>("HTTPProvider", conf->GetModule(this)->Get<Anope::string>("server", "httpd/main"));
+ if (!httpref)
+ throw ConfigException("Unable to find http reference, is m_httpd loaded?");
+ httpref->RegisterPage(&xmlrpcinterface);
}
};
diff --git a/modules/protocol/bahamut.cpp b/modules/protocol/bahamut.cpp
index 52786b361..c320f3a3e 100644
--- a/modules/protocol/bahamut.cpp
+++ b/modules/protocol/bahamut.cpp
@@ -378,7 +378,7 @@ struct IRCDMessageNick : IRCDMessage
Server *s = Server::Find(params[6]);
if (s == NULL)
{
- Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistant server " << params[6] << "?";
+ Log(LOG_DEBUG) << "User " << params[0] << " introduced from non-existent server " << params[6] << "?";
return;
}
@@ -449,7 +449,7 @@ struct IRCDMessageSJoin : IRCDMessage
sju.second = User::Find(buf);
if (!sju.second)
{
- Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << params[1];
+ Log(LOG_DEBUG) << "SJOIN for non-existent user " << buf << " on " << params[1];
continue;
}
@@ -466,11 +466,11 @@ struct IRCDMessageTopic : IRCDMessage
{
IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { }
- void Run(MessageSource &, const std::vector<Anope::string> &params) override
+ void Run(MessageSource &source, const std::vector<Anope::string> &params) override
{
Channel *c = Channel::Find(params[0]);
if (c)
- c->ChangeTopicInternal(params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
+ c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
}
};
diff --git a/modules/protocol/charybdis.cpp b/modules/protocol/charybdis.cpp
index 8477bc30e..50da90902 100644
--- a/modules/protocol/charybdis.cpp
+++ b/modules/protocol/charybdis.cpp
@@ -230,7 +230,7 @@ struct IRCDMessageEUID : IRCDMessage
}
};
-// we cant use this function from ratbox because we set a local variable here
+// we can't use this function from ratbox because we set a local variable here
struct IRCDMessageServer : IRCDMessage
{
IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
@@ -246,7 +246,7 @@ struct IRCDMessageServer : IRCDMessage
}
};
-// we cant use this function from ratbox because we set a local variable here
+// we can't use this function from ratbox because we set a local variable here
struct IRCDMessagePass : IRCDMessage
{
IRCDMessagePass(Module *creator) : IRCDMessage(creator, "PASS", 4) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
diff --git a/modules/protocol/hybrid.cpp b/modules/protocol/hybrid.cpp
index 772b9e0d9..b5c524530 100644
--- a/modules/protocol/hybrid.cpp
+++ b/modules/protocol/hybrid.cpp
@@ -1,7 +1,7 @@
/* ircd-hybrid-8 protocol module
*
* (C) 2003-2014 Anope Team
- * (C) 2012-2014 ircd-hybrid development team
+ * (C) 2012-2015 ircd-hybrid development team
*
* Please read COPYING and README for further details.
*
@@ -43,7 +43,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;
@@ -55,7 +55,7 @@ class HybridProto : public IRCDProto
CanCertFP = true;
CanSetVHost = true;
RequiresID = true;
- MaxModes = 4;
+ MaxModes = 6;
}
void SendInvite(const MessageSource &source, const Channel *c, User *u) override
@@ -73,11 +73,6 @@ class HybridProto : public IRCDProto
UplinkSocket::Message(bi) << "PRIVMSG $$" << dest->GetName() << " :" << msg;
}
- void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) override
- {
- UplinkSocket::Message(source) << "GLOBOPS :" << buf;
- }
-
void SendSQLine(User *, XLine *x) override
{
UplinkSocket::Message(FindIntroduced()) << "ENCAP * RESV " << (x->GetExpires() ? x->GetExpires() - Anope::CurTime : 0) << " " << x->GetMask() << " 0 :" << x->GetReason();
@@ -216,7 +211,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) override
@@ -224,7 +219,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() override
@@ -244,7 +239,7 @@ class HybridProto : public IRCDProto
void SendLogout(User *u) override
{
- IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 0");
+ IRCD->SendMode(Config->GetClient("NickServ"), u, "+d *");
}
void SendChannel(Channel *c) override
@@ -264,7 +259,7 @@ class HybridProto : public IRCDProto
void SendForceNickChange(User *u, const Anope::string &newnick, time_t when) 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 &) override
@@ -472,7 +467,7 @@ struct IRCDMessageSJoin : IRCDMessage
sju.second = User::Find(buf);
if (!sju.second)
{
- Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << params[1];
+ Log(LOG_DEBUG) << "SJOIN for non-existent user " << buf << " on " << params[1];
continue;
}
@@ -519,7 +514,7 @@ struct IRCDMessageTBurst : IRCDMessage
Channel *c = Channel::Find(params[1]);
if (c)
- c->ChangeTopicInternal(setter, params[4], topic_time);
+ c->ChangeTopicInternal(NULL, setter, params[4], topic_time);
}
};
@@ -553,7 +548,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) override
{
Anope::string ip = params[6];
@@ -562,7 +557,7 @@ struct IRCDMessageUID : IRCDMessage
ip.clear();
NickServ::Nick *na = NULL;
- if (params[8] != "0")
+ if (params[8] != "0" && params[8] != "*")
na = NickServ::FindNick(params[8]);
/* Source is always the server */
diff --git a/modules/protocol/inspircd20.cpp b/modules/protocol/inspircd20.cpp
index 4a74995a2..63cdc1973 100644
--- a/modules/protocol/inspircd20.cpp
+++ b/modules/protocol/inspircd20.cpp
@@ -219,6 +219,8 @@ class InspIRCd20Proto : public IRCDProto
{
Anope::string modes = "+" + u->GetModes();
UplinkSocket::Message(Me) << "UID " << u->GetUID() << " " << u->timestamp << " " << u->nick << " " << u->host << " " << u->host << " " << u->GetIdent() << " 0.0.0.0 " << u->timestamp << " " << modes << " :" << u->realname;
+ if (modes.find('o') != Anope::string::npos)
+ UplinkSocket::Message(u) << "OPERTYPE :services";
}
/* SERVER services-dev.chatspike.net password 0 :Description here */
@@ -816,7 +818,10 @@ struct IRCDMessageFHost : IRCDMessage
void Run(MessageSource &source, const std::vector<Anope::string> &params) override
{
- source.GetUser()->SetDisplayedHost(params[0]);
+ User *u = source.GetUser();
+ if (u->HasMode("CLOAK"))
+ u->RemoveModeInternal(source, ModeManager::FindUserModeByName("CLOAK"));
+ u->SetDisplayedHost(params[0]);
}
};
@@ -866,7 +871,7 @@ struct IRCDMessageFJoin : IRCDMessage
sju.second = User::Find(buf);
if (!sju.second)
{
- Log(LOG_DEBUG) << "FJOIN for nonexistant user " << buf << " on " << params[0];
+ Log(LOG_DEBUG) << "FJOIN for non-existent user " << buf << " on " << params[0];
continue;
}
@@ -917,7 +922,7 @@ struct IRCDMessageFTopic : IRCDMessage
Channel *c = Channel::Find(params[0]);
if (c)
- c->ChangeTopicInternal(params[2], params[3], Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime);
+ c->ChangeTopicInternal(NULL, params[2], params[3], Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime);
}
};
@@ -947,7 +952,15 @@ struct IRCDMessageIdle : IRCDMessage
*/
struct IRCDMessageMetadata : IRCDMessage
{
- IRCDMessageMetadata(Module *creator) : IRCDMessage(creator, "METADATA", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
+ const bool &do_topiclock, &do_mlock;
+
+ IRCDMessageMetadata(Module *creator, const bool &handle_topiclock, const bool &handle_mlock)
+ : IRCDMessage(creator, "METADATA", 3)
+ , do_topiclock(handle_topiclock)
+ , do_mlock(handle_mlock)
+ {
+ SetFlag(IRCDMESSAGE_REQUIRE_SERVER);
+ }
void Run(MessageSource &source, const std::vector<Anope::string> &params) override
{
@@ -982,8 +995,31 @@ struct IRCDMessageMetadata : IRCDMessage
Event::OnFingerprint(&Event::Fingerprint::OnFingerprint, u);
}
}
- else if (params[0][0] == '#')
+ // We deliberately ignore non-bursting servers to avoid pseudoserver fights
+ else if ((params[0][0] == '#') && (!source.GetServer()->IsSynced()))
{
+ Channel *c = Channel::Find(params[0]);
+ if (c && c->ci)
+ {
+ if ((do_mlock) && (params[1] == "mlock"))
+ {
+ ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks");
+ Anope::string modes;
+ if (modelocks)
+ modes = modelocks->GetMLockAsString(c->ci, false).replace_all_cs("+", "").replace_all_cs("-", "");
+
+ // Mode lock string is not what we say it is?
+ if (modes != params[2])
+ UplinkSocket::Message(Me) << "METADATA " << c->name << " mlock :" << modes;
+ }
+ else if ((do_topiclock) && (params[1] == "topiclock"))
+ {
+ bool mystate = c->ci->GetExt<bool>("TOPICLOCK");
+ bool serverstate = (params[2] == "1");
+ if (mystate != serverstate)
+ UplinkSocket::Message(Me) << "METADATA " << c->name << " topiclock :" << (mystate ? "1" : "");
+ }
+ }
}
else if (params[0] == "*")
{
@@ -1263,7 +1299,6 @@ class ProtoInspIRCd20 : public Module
, public EventHook<Event::DelChan>
, public EventHook<Event::MLockEvents>
, public EventHook<Event::SetChannelOption>
- , public EventHook<Event::ChannelModeUnset>
{
InspIRCd20Proto ircd_proto;
ExtensibleItem<bool> ssl;
@@ -1340,7 +1375,7 @@ class ProtoInspIRCd20 : public Module
, message_fmode(this)
, message_ftopic(this)
, message_idle(this)
- , message_metadata(this)
+ , message_metadata(this, use_server_side_topiclock, use_server_side_mlock)
, message_mode(this)
, message_nick(this)
, message_opertype(this)
@@ -1464,15 +1499,6 @@ class ProtoInspIRCd20 : public Module
return EVENT_CONTINUE;
}
-
- EventReturn OnChannelModeUnset(Channel *c, const MessageSource &setter, ChannelMode *mode, const Anope::string &param) override
- {
- if ((setter.GetUser() && setter.GetUser()->server == Me) || setter.GetServer() == Me || !setter.GetServer())
- if (mode->name == "OPERPREFIX")
- c->SetMode(c->ci->WhoSends(), mode, param, false);
-
- return EVENT_CONTINUE;
- }
};
MODULE_INIT(ProtoInspIRCd20)
diff --git a/modules/protocol/ngircd.cpp b/modules/protocol/ngircd.cpp
index 6981e32bc..b80f600e3 100644
--- a/modules/protocol/ngircd.cpp
+++ b/modules/protocol/ngircd.cpp
@@ -257,7 +257,7 @@ struct IRCDMessageChaninfo : IRCDMessage
if (params.size() == 3)
{
- c->ChangeTopicInternal(source.GetName(), params[2], Anope::CurTime);
+ c->ChangeTopicInternal(NULL, source.GetName(), params[2], Anope::CurTime);
}
else if (params.size() == 5)
{
@@ -271,9 +271,9 @@ struct IRCDMessageChaninfo : IRCDMessage
case 'l':
modes += " " + params[3];
continue;
+ }
}
- }
- c->ChangeTopicInternal(source.GetName(), params[4], Anope::CurTime);
+ c->ChangeTopicInternal(NULL, source.GetName(), params[4], Anope::CurTime);
}
c->SetModesInternal(source, modes);
@@ -451,7 +451,7 @@ struct IRCDMessageNick : IRCDMessage
Server *s = Server::Find(params[4]);
if (s == NULL)
{
- Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistant server " << params[4] << "?";
+ Log(LOG_DEBUG) << "User " << params[0] << " introduced from non-existent server " << params[4] << "?";
return;
}
User::OnIntroduce(params[0], params[2], params[3], "", "", s, params[6], Anope::CurTime, params[5], "", NULL);
@@ -500,7 +500,7 @@ struct IRCDMessageNJoin : IRCDMessage
sju.second = User::Find(buf);
if (!sju.second)
{
- Log(LOG_DEBUG) << "NJOIN for nonexistant user " << buf << " on " << params[0];
+ Log(LOG_DEBUG) << "NJOIN for non-existent user " << buf << " on " << params[0];
continue;
}
users.push_back(sju);
@@ -587,10 +587,10 @@ struct IRCDMessageTopic : IRCDMessage
Channel *c = Channel::Find(params[0]);
if (!c)
{
- Log(LOG_DEBUG) << "TOPIC for nonexistant channel " << params[0];
+ Log(LOG_DEBUG) << "TOPIC for non-existent channel " << params[0];
return;
}
- c->ChangeTopicInternal(source.GetName(), params[1], Anope::CurTime);
+ c->ChangeTopicInternal(source.GetUser(), source.GetName(), params[1], Anope::CurTime);
}
};
diff --git a/modules/protocol/ratbox.cpp b/modules/protocol/ratbox.cpp
index ec3e406b1..9e1ea0710 100644
--- a/modules/protocol/ratbox.cpp
+++ b/modules/protocol/ratbox.cpp
@@ -172,7 +172,7 @@ struct IRCDMessageTBurst : IRCDMessage
* params[0] = channel
* params[1] = ts
* params[2] = topic OR who set the topic
- * params[3] = topic if params[2] isnt the topic
+ * params[3] = topic if params[2] isn't the topic
*/
void Run(MessageSource &source, const std::vector<Anope::string> &params) override
{
@@ -185,7 +185,7 @@ struct IRCDMessageTBurst : IRCDMessage
const Anope::string &setter = params.size() == 4 ? params[2] : "",
topic = params.size() == 4 ? params[3] : params[2];
- c->ChangeTopicInternal(setter, topic, topic_time);
+ c->ChangeTopicInternal(NULL, setter, topic, topic_time);
}
};
diff --git a/modules/protocol/unreal.cpp b/modules/protocol/unreal.cpp
index b4b9893d3..6bcaaab26 100644
--- a/modules/protocol/unreal.cpp
+++ b/modules/protocol/unreal.cpp
@@ -576,7 +576,7 @@ class ChannelModeFlood : public ChannelModeParam
while (p < arg.length() && isdigit(arg[p]))
++p;
if (p == arg.length() || !(arg[p] == 'c' || arg[p] == 'j' || arg[p] == 'k' || arg[p] == 'm' || arg[p] == 'n' || arg[p] == 't'))
- continue; /* continue instead of break for forward compatability. */
+ continue; /* continue instead of break for forward compatibility. */
try
{
int v = arg.substr(0, p).is_number_only() ? convertTo<int>(arg.substr(0, p)) : 0;
@@ -745,7 +745,7 @@ struct IRCDMessageNick : IRCDMessage
Server *s = Server::Find(params[5]);
if (s == NULL)
{
- Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistant server " << params[5] << "?";
+ Log(LOG_DEBUG) << "User " << params[0] << " introduced from non-existent server " << params[5] << "?";
return;
}
@@ -829,7 +829,7 @@ struct IRCDMessageSetHost : IRCDMessage
{
User *u = source.GetUser();
- /* When a user sets +x we recieve the new host and then the mode change */
+ /* When a user sets +x we receive the new host and then the mode change */
if (u->HasMode("CLOAK"))
u->SetDisplayedHost(params[0]);
else
@@ -933,7 +933,7 @@ struct IRCDMessageSJoin : IRCDMessage
sju.second = User::Find(buf);
if (!sju.second)
{
- Log(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << params[1];
+ Log(LOG_DEBUG) << "SJOIN for non-existent user " << buf << " on " << params[1];
continue;
}
@@ -983,7 +983,7 @@ struct IRCDMessageTopic : IRCDMessage
{
Channel *c = Channel::Find(params[0]);
if (c)
- c->ChangeTopicInternal(params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
+ c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
}
};
diff --git a/modules/pseudoclients/botserv/botserv.cpp b/modules/pseudoclients/botserv/botserv.cpp
index 0042b6267..0b51691fc 100644
--- a/modules/pseudoclients/botserv/botserv.cpp
+++ b/modules/pseudoclients/botserv/botserv.cpp
@@ -103,7 +103,7 @@ class BotServCore : public Module, public BotServ::BotServService
{
/**
* We let the bot join even if it was an ignored user, as if we don't,
- * and the ignored user doesnt just leave, the bot will never
+ * and the ignored user doesn't just leave, the bot will never
* make it into the channel, leaving the channel botless even for
* legit users - Rob
**/
@@ -121,8 +121,8 @@ class BotServCore : public Module, public BotServ::BotServService
/* Channel is persistent, it shouldn't be deleted and the service bot should stay */
if (c->ci && persist && persist->HasExt(c->ci))
return;
-
- /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediatly
+
+ /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediately
* We also don't part the bot here either, if necessary we will part it after the sync
*/
if (c->syncing)
diff --git a/modules/pseudoclients/chanserv/channel.cpp b/modules/pseudoclients/chanserv/channel.cpp
index 8b349dc1f..b24edcc0c 100644
--- a/modules/pseudoclients/chanserv/channel.cpp
+++ b/modules/pseudoclients/chanserv/channel.cpp
@@ -194,7 +194,7 @@ ChanServ::ChanAccess *ChannelImpl::GetAccess(unsigned index)
return a.size() > index ? a[index] : nullptr;
}
-ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u)
+ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u, bool updateLastUsed)
{
ChanServ::AccessGroup group;
@@ -223,7 +223,8 @@ ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u)
if (group.founder || !group.empty())
{
- this->SetLastUsed(Anope::CurTime);
+ if (updateLastUsed)
+ this->SetLastUsed(Anope::CurTime);
for (unsigned i = 0; i < group.size(); ++i)
group[i]->SetLastSeen(Anope::CurTime);
@@ -232,7 +233,7 @@ ChanServ::AccessGroup ChannelImpl::AccessFor(const User *u)
return group;
}
-ChanServ::AccessGroup ChannelImpl::AccessFor(NickServ::Account *nc)
+ChanServ::AccessGroup ChannelImpl::AccessFor(NickServ::Account *nc, bool updateLastUsed)
{
ChanServ::AccessGroup group;
@@ -248,7 +249,8 @@ ChanServ::AccessGroup ChannelImpl::AccessFor(NickServ::Account *nc)
}
if (group.founder || !group.empty())
- this->SetLastUsed(Anope::CurTime);
+ if (updateLastUsed)
+ this->SetLastUsed(Anope::CurTime);
/* don't update access last seen here, this isn't the user requesting access */
@@ -362,6 +364,13 @@ void ChannelImpl::SetLevel(const Anope::string &priv, int16_t level)
return;
}
+ ChanServ::Privilege *p = ChanServ::service ? ChanServ::service->FindPrivilege(priv) : nullptr;
+ if (!p)
+ {
+ Log(LOG_DEBUG) << "Unknown privilege " + priv;
+ return;
+ }
+
ChanServ::Level *l = ChanServ::level.Create();
l->SetChannel(this);
l->SetName(priv);
diff --git a/modules/pseudoclients/chanserv/channel.h b/modules/pseudoclients/chanserv/channel.h
index 18a4be5d6..86e42a8f9 100644
--- a/modules/pseudoclients/chanserv/channel.h
+++ b/modules/pseudoclients/chanserv/channel.h
@@ -50,8 +50,8 @@ class ChannelImpl : public ChanServ::Channel
void SetSuccessor(NickServ::Account *nc) override;
NickServ::Account *GetSuccessor() override;
ChanServ::ChanAccess *GetAccess(unsigned index) /*const*/ override;
- ChanServ::AccessGroup AccessFor(const User *u) override;
- ChanServ::AccessGroup AccessFor(NickServ::Account *nc) override;
+ ChanServ::AccessGroup AccessFor(const User *u, bool = true) override;
+ ChanServ::AccessGroup AccessFor(NickServ::Account *nc, bool = true) override;
unsigned GetAccessCount()/* const*/ override;
unsigned GetDeepAccessCount() const override;
void ClearAccess() override;
diff --git a/modules/pseudoclients/nickserv/nickserv.cpp b/modules/pseudoclients/nickserv/nickserv.cpp
index ee6068ef1..26f1457cc 100644
--- a/modules/pseudoclients/nickserv/nickserv.cpp
+++ b/modules/pseudoclients/nickserv/nickserv.cpp
@@ -20,6 +20,9 @@
#include "accounttype.h"
#include "modetype.h"
+class NickServCollide;
+static std::set<NickServCollide *> collides;
+
/** Timer for colliding nicks to force people off of nicknames
*/
class NickServCollide : public Timer
@@ -32,6 +35,22 @@ class NickServCollide : public Timer
public:
NickServCollide(Module *me, NickServ::NickServService *nss, User *user, NickServ::Nick *nick, time_t delay) : Timer(me, delay), service(nss), u(user), ts(user->timestamp), na(nick)
{
+ collides.insert(this);
+ }
+
+ ~NickServCollide()
+ {
+ collides.erase(this);
+ }
+
+ NickServ::Nick *GetNick()
+ {
+ return na;
+ }
+
+ User *GetUser()
+ {
+ return u;
}
void Tick(time_t t) override
@@ -429,6 +448,16 @@ class NickServCore : public Module, public NickServ::NickServService
"Your privacy is respected; this e-mail won't be given to\n"
"any third-party person."), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str());
}
+
+ for (std::set<NickServCollide *>::iterator it = collides.begin(); it != collides.end(); ++it)
+ {
+ NickServCollide *c = *it;
+ if (c->GetUser() == u && c->GetNick() && c->GetNick()->GetAccount() == u->Account())
+ {
+ delete c;
+ break;
+ }
+ }
}
void OnNickGroup(User *u, NickServ::Nick *target) override
@@ -632,8 +661,23 @@ class NickServCore : public Module, public NickServ::NickServService
++it;
ir->Release(m);
+#if 0
+ ir->holds.erase(m);
+ if (ir->holds.empty() && ir->dispatched)
+ {
+ if (!ir->success)
+ ir->OnFail();
+ delete ir;
+ continue;
+ }
+
if (ir->GetOwner() == m)
+ {
+ if (!ir->success)
+ ir->OnFail();
delete ir;
+ }
+#endif
}
}
};
diff --git a/modules/pseudoclients/operserv.cpp b/modules/pseudoclients/operserv.cpp
index fe187b70c..0a4f1b692 100644
--- a/modules/pseudoclients/operserv.cpp
+++ b/modules/pseudoclients/operserv.cpp
@@ -139,9 +139,13 @@ class SQLineManager : public XLineManager
if (std::regex_match(c->name.str(), *x->regex))
return x;
}
- else if (Anope::Match(c->name, x->GetMask(), false, true))
+ else
{
- return x;
+ if (x->GetMask().empty() || x->GetMask()[0] != '#')
+ continue;
+
+ if (Anope::Match(c->name, x->GetMask(), false, true))
+ return x;
}
}
return nullptr;
diff --git a/modules/webcpanel/pages/index.cpp b/modules/webcpanel/pages/index.cpp
index e3a8de96c..551b73a0e 100644
--- a/modules/webcpanel/pages/index.cpp
+++ b/modules/webcpanel/pages/index.cpp
@@ -31,6 +31,12 @@ class WebpanelRequest : public NickServ::IdentifyRequestListener
return;
}
+ if (na->GetAccount()->HasFieldS("NS_SUSPENDED"))
+ {
+ this->OnFail(req);
+ return;
+ }
+
Anope::string id;
for (int i = 0; i < 64; ++i)
{