diff options
-rw-r--r-- | conf/inspircd.conf.example | 4 | ||||
-rw-r--r-- | conf/modules.conf.example | 15 | ||||
-rw-r--r-- | include/configreader.h | 12 | ||||
-rw-r--r-- | include/modules.h | 8 | ||||
-rw-r--r-- | src/configreader.cpp | 9 | ||||
-rw-r--r-- | src/modules.cpp | 1 | ||||
-rw-r--r-- | src/modules/m_blockcaps.cpp | 8 | ||||
-rw-r--r-- | src/modules/m_blockcolor.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_censor.cpp | 7 | ||||
-rw-r--r-- | src/modules/m_chanfilter.cpp | 5 | ||||
-rw-r--r-- | src/modules/m_exemptchanops.cpp | 130 | ||||
-rw-r--r-- | src/modules/m_messageflood.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_nickflood.cpp | 8 | ||||
-rw-r--r-- | src/modules/m_noctcp.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_nonicks.cpp | 5 | ||||
-rw-r--r-- | src/modules/m_nonotice.cpp | 7 | ||||
-rw-r--r-- | src/modules/m_services_account.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_stripcolor.cpp | 8 |
18 files changed, 193 insertions, 56 deletions
diff --git a/conf/inspircd.conf.example b/conf/inspircd.conf.example index cfdba6c25..dcfaf428e 100644 --- a/conf/inspircd.conf.example +++ b/conf/inspircd.conf.example @@ -522,10 +522,6 @@ # banned from the server. moronbanner="You're banned! Email haha@abuse.com with the ERROR line below for help." - # exemptchanops: Defines what channel modes channel operators are - # exempt from. Supported modes are +TCGfcSFBgN. Defaults to off. - exemptchanops="" - # invitebypassmodes: This allows /invite to bypass other channel modes. # (Such as +k, +j, +l, etc) invitebypassmodes="yes"> diff --git a/conf/modules.conf.example b/conf/modules.conf.example index 9bc9dca05..691068a73 100644 --- a/conf/modules.conf.example +++ b/conf/modules.conf.example @@ -697,6 +697,21 @@ # http://wiki.inspircd.org/Modules/dnsbl # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Exempt Channel Operators Module: Provides support for allowing # +# channel operators to be exempt from some channel modes. Supported # +# modes are blockcaps, noctcp, blockcolor, nickflood, flood, censor, # +# filter, regmoderated, nonick, nonotice, and stripcolor. # +#<module name="m_exemptchanops.so"> # +# # +#-#-#-#-#-#-#-#-#-#- EXEMPTCHANOPS CONFIGURATION -#-#-#-#-#-#-#-#-#-# +# alwaysexempt - Modes channel operators are always exempt from, +# regardless of channel setting. +# neverexempt - Modes channel operators are never exempt from, +# regardless of channel setting. +#<exemptchanops alwaysexempt="nickflood censor flood filter" neverexempt="regmoderated"> + + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Filter module: Provides message filtering, similar to SPAMFILTER. #<module name="m_filter.so"> # # diff --git a/include/configreader.h b/include/configreader.h index 893259b7c..bc5a09f02 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -14,13 +14,6 @@ #ifndef INSPIRCD_CONFIGREADER #define INSPIRCD_CONFIGREADER -/* handy defines */ - -/** Determines if a channel op is exempt from given mode m, - * in config of server instance s. - */ -#define CHANOPS_EXEMPT(m) (ServerInstance->Config->ExemptChanOps[(unsigned char)m]) - #include <sstream> #include <string> #include <vector> @@ -385,11 +378,6 @@ class CoreExport ServerConfig : public classbase */ bool HideModeLists[256]; - /** If this is set to true, then channel operators - * are exempt from this channel mode. Used for +Sc etc. - */ - bool ExemptChanOps[256]; - /** The number of seconds the DNS subsystem * will wait before timing out any request. */ diff --git a/include/modules.h b/include/modules.h index 972dabb43..0a1c759e5 100644 --- a/include/modules.h +++ b/include/modules.h @@ -341,7 +341,7 @@ enum Implementation I_OnPostOper, I_OnSyncNetwork, I_OnSetAway, I_OnUserList, I_OnPostCommand, I_OnPostJoin, I_OnWhoisLine, I_OnBuildNeighborList, I_OnGarbageCollect, I_OnText, I_OnPassCompare, I_OnRunTestSuite, I_OnNamesListItem, I_OnNumeric, I_OnHookIO, - I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, + I_OnPreRehash, I_OnModuleRehash, I_OnSendWhoLine, I_OnChangeIdent, I_OnChannelRestrictionApply, I_END }; @@ -1279,6 +1279,12 @@ class CoreExport Module : public Extensible * @param line The raw line to send; modifiable, if empty no line will be returned. */ virtual void OnSendWhoLine(User* source, User* user, Channel* channel, std::string& line); + + /** Called to check whether a channel restriction mode applies to a user on it + * @return MOD_RES_DENY to apply the restriction, MOD_RES_ALLOW to bypass + * the restriction, or MOD_RES_PASSTHRU to check restriction status normally + */ + virtual ModResult OnChannelRestrictionApply(Membership* memb, Channel* chan, const char* restriction); }; diff --git a/src/configreader.cpp b/src/configreader.cpp index ac0dc2596..7248ff099 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -382,14 +382,6 @@ static bool ValidateModeLists(ServerConfig* conf, const char*, const char*, Valu return true; } -static bool ValidateExemptChanOps(ServerConfig* conf, const char*, const char*, ValueItem &data) -{ - memset(conf->ExemptChanOps, 0, sizeof(conf->ExemptChanOps)); - for (const unsigned char* x = (const unsigned char*)data.GetString(); *x; ++x) - conf->ExemptChanOps[*x] = true; - return true; -} - static bool ValidateInvite(ServerConfig* conf, const char*, const char*, ValueItem &data) { const std::string& v = data.GetValue(); @@ -801,7 +793,6 @@ static const InitialConfig Values[] = { {"security", "announceinvites", "1", NULL, DT_NOTHING, ValidateInvite}, {"options", "hostintopic", "1", new ValueContainerBool (&ServerConfig::FullHostInTopic), DT_BOOLEAN, NULL}, {"security", "hidemodes", "", NULL, DT_NOTHING, ValidateModeLists}, - {"options", "exemptchanops","", NULL, DT_NOTHING, ValidateExemptChanOps}, {"security", "maxtargets", "20", new ValueContainerUInt (&ServerConfig::MaxTargets), DT_INTEGER, ValidateMaxTargets}, {"options", "defaultmodes", "nt", new ValueContainerString (&ServerConfig::DefaultModes), DT_CHARPTR, NULL}, {"pid", "file", "", new ValueContainerString (&ServerConfig::PID), DT_CHARPTR, NULL}, diff --git a/src/modules.cpp b/src/modules.cpp index 921e710f9..3e9fa84de 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -150,6 +150,7 @@ void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; } void Module::OnHookIO(StreamSocket*, ListenSocketBase*) { } void Module::OnSendWhoLine(User*, User*, Channel*, std::string&) { } +ModResult Module::OnChannelRestrictionApply(Membership*, Channel*, const char*) { return MOD_RES_PASSTHRU; } ModuleManager::ModuleManager() : ModCount(0) { diff --git a/src/modules/m_blockcaps.cpp b/src/modules/m_blockcaps.cpp index 7a696035a..e21e1da88 100644 --- a/src/modules/m_blockcaps.cpp +++ b/src/modules/m_blockcaps.cpp @@ -16,7 +16,7 @@ /* $ModDesc: Provides support to block all-CAPS channel messages and notices */ -/** Handles the +P channel mode +/** Handles the +B channel mode */ class BlockCaps : public SimpleChannelModeHandler { @@ -59,11 +59,11 @@ public: return MOD_RES_PASSTHRU; Channel* c = (Channel*)dest; + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"blockcaps")); - if (CHANOPS_EXEMPT('B') && c->GetPrefixValue(user) == OP_VALUE) - { + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet('B'))) { diff --git a/src/modules/m_blockcolor.cpp b/src/modules/m_blockcolor.cpp index eba648126..9075bd8c7 100644 --- a/src/modules/m_blockcolor.cpp +++ b/src/modules/m_blockcolor.cpp @@ -47,11 +47,11 @@ class ModuleBlockColour : public Module if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = (Channel*)dest; + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"blockcolor")); - if (CHANOPS_EXEMPT('c') && c->GetPrefixValue(user) == OP_VALUE) - { + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } if (!c->GetExtBanStatus(user, 'c').check(!c->IsModeSet('c'))) { diff --git a/src/modules/m_censor.cpp b/src/modules/m_censor.cpp index fc640624c..4b08e3711 100644 --- a/src/modules/m_censor.cpp +++ b/src/modules/m_censor.cpp @@ -75,10 +75,11 @@ class ModuleCensor : public Module { active = ((Channel*)dest)->IsModeSet('G'); Channel* c = (Channel*)dest; - if (CHANOPS_EXEMPT('G') && c->GetPrefixValue(user) == OP_VALUE) - { + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"censor")); + + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } } if (!active) diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp index d87de1207..cb5f22855 100644 --- a/src/modules/m_chanfilter.cpp +++ b/src/modules/m_chanfilter.cpp @@ -85,7 +85,10 @@ class ModuleChanFilter : public Module virtual ModResult ProcessMessages(User* user,Channel* chan,std::string &text) { - if (!IS_LOCAL(user) || (CHANOPS_EXEMPT('g') && chan->GetPrefixValue(user) == OP_VALUE)) + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (chan->GetUser(user),chan,"filter")); + + if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; modelist* list = cf.extItem.get(chan); diff --git a/src/modules/m_exemptchanops.cpp b/src/modules/m_exemptchanops.cpp new file mode 100644 index 000000000..ae2a80b02 --- /dev/null +++ b/src/modules/m_exemptchanops.cpp @@ -0,0 +1,130 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#define _CRT_SECURE_NO_DEPRECATE +#define _SCL_SECURE_NO_DEPRECATE + +#include "inspircd.h" +#include "u_listmode.h" + +/* $ModDesc: Provides the ability to allow channel operators to be exempt from certain modes. */ +/* $ModDep: ../../include/u_listmode.h */ + +/** Handles channel mode +X + */ +class ExemptChanOps : public ListModeBase +{ + public: + ExemptChanOps(Module* Creator) : ListModeBase(Creator, "exemptchanops", 'X', "End of channel exemptchanops list", 954, 953, false, "exemptchanops") { } + + virtual bool ValidateParam(User* user, Channel* chan, std::string &word) + { + if ((word.length() > 35) || (word.empty())) + { + user->WriteNumeric(955, "%s %s %s :word is too %s for exemptchanops list",user->nick.c_str(), chan->name.c_str(), word.c_str(), (word.empty() ? "short" : "long")); + return false; + } + + return true; + } + + virtual bool TellListTooLong(User* user, Channel* chan, std::string &word) + { + user->WriteNumeric(959, "%s %s %s :Channel exemptchanops list is full", user->nick.c_str(), chan->name.c_str(), word.c_str()); + return true; + } + + virtual void TellAlreadyOnList(User* user, Channel* chan, std::string &word) + { + user->WriteNumeric(957, "%s %s :The word %s is already on the exemptchanops list",user->nick.c_str(), chan->name.c_str(), word.c_str()); + } + + virtual void TellNotSet(User* user, Channel* chan, std::string &word) + { + user->WriteNumeric(958, "%s %s :No such exemptchanops word is set",user->nick.c_str(), chan->name.c_str()); + } +}; + +class ModuleExemptChanOps : public Module +{ + ExemptChanOps ec; + std::string alwaysexempt, neverexempt; + + public: + + ModuleExemptChanOps() + : ec(this) + { + if (!ServerInstance->Modes->AddMode(&ec)) + throw ModuleException("Could not add new modes!"); + + ec.DoImplements(this); + Implementation eventlist[] = { I_OnChannelDelete, I_OnChannelRestrictionApply, I_OnRehash, I_OnSyncChannel }; + ServerInstance->Modules->Attach(eventlist, this, 4); + + OnRehash(NULL); + ServerInstance->Modules->PublishInterface("ChannelBanList", this); + } + + virtual Version GetVersion() + { + return Version("Provides the ability to allow channel operators to be exempt from certain modes.",VF_VENDOR|VF_COMMON,API_VERSION); + } + + virtual void OnRehash(User* user) + { + ConfigReader Conf; + alwaysexempt = Conf.ReadValue("exemptchanops", "alwaysexempt", 0); + neverexempt = Conf.ReadValue("exemptchanops", "neverexempt", 0); + ec.DoRehash(); + } + + virtual void OnCleanup(int target_type, void* item) + { + ec.DoCleanup(target_type, item); + } + + virtual void OnSyncChannel(Channel* chan, Module* proto, void* opaque) + { + ec.DoSyncChannel(chan, proto, opaque); + } + + virtual ModResult OnChannelRestrictionApply(Membership* memb, Channel* chan, const char* restriction) + { + irc::spacesepstream allowstream(alwaysexempt), denystream(neverexempt); + std::string current; + + if (memb->getRank() != OP_VALUE) + return MOD_RES_PASSTHRU; // They're not opped, so we don't exempt them + while(denystream.GetToken(current)) + if (!strcasecmp(restriction, current.c_str())) return MOD_RES_PASSTHRU; // This mode is set to never allow exemptions in the config + while(allowstream.GetToken(current)) + if (!strcasecmp(restriction, current.c_str())) return MOD_RES_ALLOW; // This mode is set to always allow exemptions in the config + + modelist* list = ec.extItem.get(chan); + + if (!list) return MOD_RES_PASSTHRU; + for (modelist::iterator i = list->begin(); i != list->end(); ++i) + if (!strcasecmp(restriction, i->mask.c_str())) + return MOD_RES_ALLOW; // They're opped, and the channel lets ops bypass this mode. Allow regardless of restrictions + + return MOD_RES_PASSTHRU; + } + + virtual ~ModuleExemptChanOps() + { + ServerInstance->Modules->UnpublishInterface("ChannelBanList", this); + } +}; + +MODULE_INIT(ModuleExemptChanOps) diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index 542aedd41..8a521ebab 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -207,10 +207,10 @@ class ModuleMsgFlood : public Module ModResult ProcessMessages(User* user,Channel* dest, const std::string &text) { - if (!IS_LOCAL(user) || (CHANOPS_EXEMPT('f') && dest->GetPrefixValue(user) == OP_VALUE)) - { + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (dest->GetUser(user),dest,"flood")); + if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } floodsettings *f = mf.ext.get(dest); if (f) diff --git a/src/modules/m_nickflood.cpp b/src/modules/m_nickflood.cpp index 748ecf1d5..26d04835a 100644 --- a/src/modules/m_nickflood.cpp +++ b/src/modules/m_nickflood.cpp @@ -213,11 +213,13 @@ class ModuleNickFlood : public Module for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) { Channel *channel = *i; + ModResult res; nickfloodsettings *f = nf.ext.get(channel); if (f) { - if (CHANOPS_EXEMPT('F') && channel->GetPrefixValue(user) == OP_VALUE) + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (channel->GetUser(user),channel,"nickflood")); + if (res == MOD_RES_ALLOW) continue; if (f->islocked()) @@ -250,11 +252,13 @@ class ModuleNickFlood : public Module for (UCListIter i = user->chans.begin(); i != user->chans.end(); ++i) { Channel *channel = *i; + ModResult res; nickfloodsettings *f = nf.ext.get(channel); if (f) { - if (CHANOPS_EXEMPT('F') && channel->GetPrefixValue(user) == OP_VALUE) + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (channel->GetUser(user),channel,"nickflood")); + if (res == MOD_RES_ALLOW) return; /* moved this here to avoid incrementing the counter for nick diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index 5dfbf76d2..1d360abe1 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -78,11 +78,11 @@ class ModuleNoCTCP : public Module if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = (Channel*)dest; + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"noctcp")); - if (CHANOPS_EXEMPT('C') && c->GetPrefixValue(user) == OP_VALUE) - { + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } if (!c->GetExtBanStatus(user, 'C').check(!c->IsModeSet('C'))) { diff --git a/src/modules/m_nonicks.cpp b/src/modules/m_nonicks.cpp index 22b0067cc..3e378d59f 100644 --- a/src/modules/m_nonicks.cpp +++ b/src/modules/m_nonicks.cpp @@ -85,7 +85,10 @@ class ModuleNoNickChange : public Module { Channel* curr = *i; - if (CHANOPS_EXEMPT('N') && curr->GetPrefixValue(user) == OP_VALUE) + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (curr->GetUser(user),curr,"nonick")); + + if (res == MOD_RES_ALLOW) continue; if (!curr->GetExtBanStatus(user, 'N').check(!curr->IsModeSet('N'))) diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp index 169626e61..188f08908 100644 --- a/src/modules/m_nonotice.cpp +++ b/src/modules/m_nonotice.cpp @@ -42,6 +42,7 @@ class ModuleNoNotice : public Module virtual ModResult OnUserPreNotice(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list) { + ModResult res; if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user))) { Channel* c = (Channel*)dest; @@ -52,11 +53,9 @@ class ModuleNoNotice : public Module // ulines are exempt. return MOD_RES_PASSTHRU; } - else if (CHANOPS_EXEMPT('T') && c->GetPrefixValue(user) == OP_VALUE) - { - // channel ops are exempt if set in conf. + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"nonotice")); + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } else { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s %s :Can't send NOTICE to channel (+T set)",user->nick.c_str(), c->name.c_str()); diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp index 45baaf90e..7f4e6d43f 100644 --- a/src/modules/m_services_account.cpp +++ b/src/modules/m_services_account.cpp @@ -173,8 +173,10 @@ class ModuleServicesAccount : public Module if (target_type == TYPE_CHANNEL) { Channel* c = (Channel*)dest; + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (c->GetUser(user),c,"regmoderated")); - if (c->IsModeSet('M') && !is_registered) + if (c->IsModeSet('M') && !is_registered && res != MOD_RES_ALLOW) { // user messaging a +M channel and is not registered user->WriteNumeric(477, ""+std::string(user->nick)+" "+std::string(c->name)+" :You need to be identified to a registered account to message this channel"); diff --git a/src/modules/m_stripcolor.cpp b/src/modules/m_stripcolor.cpp index e610987d3..2c2b2363f 100644 --- a/src/modules/m_stripcolor.cpp +++ b/src/modules/m_stripcolor.cpp @@ -110,13 +110,11 @@ class ModuleStripColor : public Module else if (target_type == TYPE_CHANNEL) { Channel* t = (Channel*)dest; + ModResult res; + FIRST_MOD_RESULT(OnChannelRestrictionApply, res, (t->GetUser(user),t,"stripcolor")); - // check if we allow ops to bypass filtering, if we do, check if they're opped accordingly. - // note: short circut logic here, don't wreck it. -- w00t - if (CHANOPS_EXEMPT('S') && t->GetPrefixValue(user) == OP_VALUE) - { + if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - } active = !t->GetExtBanStatus(user, 'S').check(!t->IsModeSet('S')); } |