From 6eae25cd36a95adff860ebc6b109676a7f3bcd5c Mon Sep 17 00:00:00 2001 From: danieldg Date: Sun, 13 Sep 2009 20:33:56 +0000 Subject: [PATCH] Fix access checks on chanprotect preventing use of SAMODE git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11717 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/mode.h | 12 +++- src/mode.cpp | 40 ++++++++---- src/modules/m_chanprotect.cpp | 119 ++++++++++++++-------------------- 3 files changed, 85 insertions(+), 86 deletions(-) diff --git a/include/mode.h b/include/mode.h index db115a3c9..c0cb5b0fc 100644 --- a/include/mode.h +++ b/include/mode.h @@ -230,6 +230,16 @@ class CoreExport ModeHandler : public classbase */ virtual std::string GetUserParameter(User* useor); + /** + * Called when a channel mode change access check for your mode occurs. + * @param source Contains the user setting the mode. + * @param channel contains the destination channel the modes are being set on. + * @param parameter The parameter for your mode. This is modifiable. + * @param adding This value is true when the mode is being set, or false when it is being unset. + * @return allow, deny, or passthru to check against the required level + */ + virtual ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding); + /** * Called when a mode change for your mode occurs. * @param source Contains the user setting the mode. @@ -312,7 +322,7 @@ class CoreExport ModeHandler : public classbase * @param channel The channel which the server wants to remove your mode from */ virtual void RemoveMode(Channel* channel, irc::modestacker* stack = NULL); - + inline unsigned int GetLevelRequired() const { return levelrequired; } }; diff --git a/src/mode.cpp b/src/mode.cpp index 2089ad140..56524ff00 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -104,6 +104,11 @@ std::string ModeHandler::GetUserParameter(User* user) return ""; } +ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool) +{ + return MOD_RES_PASSTHRU; +} + ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool) { return MODEACTION_DENY; @@ -270,21 +275,28 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW)) { - unsigned int neededrank = mh->GetLevelRequired(); - /* Compare our rank on the channel against the rank of the required prefix, - * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown - * in NAMES(X) are not in rank order, we know the most powerful mode is listed - * first, so we don't need to iterate, we just look up the first instead. - */ - unsigned int ourrank = chan->GetPrefixValue(user); - if (ourrank < neededrank) - { - /* Bog off */ - // TODO replace with a real search for the proper prefix - char needed = neededrank > HALFOP_VALUE ? '@' : '%'; - user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c", - user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar); + MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding); + + if (MOD_RESULT == MOD_RES_DENY) return MODEACTION_DENY; + if (MOD_RESULT == MOD_RES_PASSTHRU) + { + unsigned int neededrank = mh->GetLevelRequired(); + /* Compare our rank on the channel against the rank of the required prefix, + * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown + * in NAMES(X) are not in rank order, we know the most powerful mode is listed + * first, so we don't need to iterate, we just look up the first instead. + */ + unsigned int ourrank = chan->GetPrefixValue(user); + if (ourrank < neededrank) + { + /* Bog off */ + // TODO replace with a real search for the proper prefix + char needed = neededrank > HALFOP_VALUE ? '@' : '%'; + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c", + user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar); + return MODEACTION_DENY; + } } } diff --git a/src/modules/m_chanprotect.cpp b/src/modules/m_chanprotect.cpp index 56d107c71..4d046b415 100644 --- a/src/modules/m_chanprotect.cpp +++ b/src/modules/m_chanprotect.cpp @@ -24,7 +24,6 @@ class FounderProtectBase { private: - InspIRCd* const MyInstance; const std::string type; const char mode; const int list; @@ -33,14 +32,14 @@ class FounderProtectBase bool& remove_own_privs; bool& remove_other_privs; public: - FounderProtectBase(InspIRCd* Instance, char Mode, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) : - MyInstance(Instance), type(mtype), mode(Mode), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others) + FounderProtectBase(char Mode, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) : + type(mtype), mode(Mode), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others) { } ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string ¶meter) { - User* x = MyInstance->FindNick(parameter); + User* x = ServerInstance->FindNick(parameter); if (x) { Membership* memb = channel->GetUser(x); @@ -68,7 +67,7 @@ class FounderProtectBase const UserMembList* cl = channel->GetUsers(); std::vector mode_junk; mode_junk.push_back(channel->name); - irc::modestacker modestack(MyInstance, false); + irc::modestacker modestack(ServerInstance, false); std::deque stackresult; for (UserMembCIter i = cl->begin(); i != cl->end(); i++) @@ -88,7 +87,7 @@ class FounderProtectBase while (modestack.GetStackedLine(stackresult)) { mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end()); - MyInstance->SendMode(mode_junk, MyInstance->FakeClient); + ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient); mode_junk.erase(mode_junk.begin() + 1, mode_junk.end()); } } @@ -118,9 +117,9 @@ class FounderProtectBase class ChanFounder : public ModeHandler, public FounderProtectBase { public: - ChanFounder(InspIRCd* Instance, Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others) + ChanFounder(Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others) : ModeHandler(Creator, 'q', PARAM_ALWAYS, MODETYPE_CHANNEL), - FounderProtectBase(Instance, 'q', "founder", 386, 387, depriv_self, depriv_others) + FounderProtectBase('q', "founder", 386, 387, depriv_self, depriv_others) { ModeHandler::list = true; prefix = my_prefix; @@ -146,48 +145,34 @@ class ChanFounder : public ModeHandler, public FounderProtectBase void RemoveMode(User* user, irc::modestacker* stack) { } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + + ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding) { User* theuser = ServerInstance->FindNick(parameter); + // remove own privs? + if (source == theuser && !adding && FounderProtectBase::remove_own_privs) + return MOD_RES_ALLOW; - if (!theuser) - { - return MODEACTION_DENY; - } - - if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel)) - { - return MODEACTION_ALLOW; - } - - char isoverride=0; - Module *Override = ServerInstance->Modules->FindFeature("Override"); - if (Override) + if (!adding && FounderProtectBase::CanRemoveOthers(source, channel)) { - OVRrequest ovr(NULL,Override,source,"OTHERMODE"); - const char * tmp = ovr.Send(); - isoverride = tmp[0]; - } - // source is a server, or ulined, we'll let them +-q the user. - if (!IS_LOCAL(source) || - ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || - (ServerInstance->ULine(source->nick.c_str())) || - (ServerInstance->ULine(source->server)) || - (!*source->server) || - isoverride) - { - return MODEACTION_ALLOW; + return MOD_RES_PASSTHRU; } else { - // whoops, someones being naughty! source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str()); - parameter.clear(); - return MODEACTION_DENY; + return MOD_RES_DENY; } } + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + { + User* theuser = ServerInstance->FindNick(parameter); + + if (!theuser) + return MODEACTION_DENY; + return MODEACTION_ALLOW; + } + void DisplayList(User* user, Channel* channel) { FounderProtectBase::DisplayList(user,channel); @@ -199,9 +184,9 @@ class ChanFounder : public ModeHandler, public FounderProtectBase class ChanProtect : public ModeHandler, public FounderProtectBase { public: - ChanProtect(InspIRCd* Instance, Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others) + ChanProtect(Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others) : ModeHandler(Creator, 'a', PARAM_ALWAYS, MODETYPE_CHANNEL), - FounderProtectBase(Instance,'a',"protected user", 388, 389, depriv_self, depriv_others) + FounderProtectBase('a',"protected user", 388, 389, depriv_self, depriv_others) { ModeHandler::list = true; prefix = my_prefix; @@ -228,46 +213,38 @@ class ChanProtect : public ModeHandler, public FounderProtectBase { } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding) { User* theuser = ServerInstance->FindNick(parameter); + // source has +q + if (channel->GetPrefixValue(source) > PROTECT_VALUE) + return MOD_RES_ALLOW; - if (!theuser) - return MODEACTION_DENY; - - if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel)) - { - return MODEACTION_ALLOW; - } + // removing own privs? + if (source == theuser && !adding && FounderProtectBase::remove_own_privs) + return MOD_RES_ALLOW; - char isoverride=0; - Module *Override = ServerInstance->Modules->FindFeature("Override"); - if (Override) + if (!adding && FounderProtectBase::CanRemoveOthers(source, channel)) { - OVRrequest ovr(NULL,Override,source,"OTHERMODE"); - const char * tmp = ovr.Send(); - isoverride = tmp[0]; - } - // source has +q, is a server, or ulined, we'll let them +-a the user. - if (!IS_LOCAL(source) || - ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) || - (ServerInstance->ULine(source->nick.c_str())) || - (ServerInstance->ULine(source->server)) || - (!*source->server) || - (channel->GetPrefixValue(source) > PROTECT_VALUE) || - isoverride - ) - { - return MODEACTION_ALLOW; + return MOD_RES_PASSTHRU; } else { - // bzzzt, wrong answer! source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str()); - return MODEACTION_DENY; + return MOD_RES_DENY; } } + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + { + User* theuser = ServerInstance->FindNick(parameter); + + if (!theuser) + return MODEACTION_DENY; + + return MODEACTION_ALLOW; + } + void DisplayList(User* user, Channel* channel) { FounderProtectBase::DisplayList(user, channel); @@ -298,8 +275,8 @@ class ModuleChanProtect : public Module /* Initialise module variables */ - cp = new ChanProtect(ServerInstance, this, APrefix, DeprivSelf, DeprivOthers); - cf = new ChanFounder(ServerInstance, this, QPrefix, DeprivSelf, DeprivOthers); + cp = new ChanProtect(this, APrefix, DeprivSelf, DeprivOthers); + cf = new ChanFounder(this, QPrefix, DeprivSelf, DeprivOthers); if (!ServerInstance->Modes->AddMode(cp) || !ServerInstance->Modes->AddMode(cf)) { -- 2.39.5