diff options
| author | Adam <Adam@anope.org> | 2015-10-27 18:57:37 -0400 |
|---|---|---|
| committer | Adam <Adam@anope.org> | 2015-10-27 18:58:48 -0400 |
| commit | 64dac60071fab652745a6e7a06cf6b7bdbbd3625 (patch) | |
| tree | f8f30161150451672b381f6370a8fdcab654bbb8 /modules | |
| parent | 162fdbe5815bbdf187f549fefac94ff476d72e62 (diff) | |
| parent | 830361e97d03c74e54cb1cf1bbf329dffdeb66f7 (diff) | |
Merge branch '2.0' into 2.1
Diffstat (limited to 'modules')
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 ¶m) override; EventReturn OnChannelModeUnset(Channel *c, const MessageSource &setter, ChannelMode *mode, const Anope::string ¶m) 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> ¶ms) override + void Run(MessageSource &source, const std::vector<Anope::string> ¶ms) 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> ¶ms) 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> ¶ms) 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> ¶ms) 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 ¶m) 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> ¶ms) 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) { |
