X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_denychans.cpp;h=4bddcf1cda30c3f13801c4da25e19d38683f8dfc;hb=56375392ba94f2552bbeeeab4fd39e1e50295525;hp=6378ba2733c75b0f2aa23e283d31ec0896fd3a44;hpb=3a3ff949670c61a4a8856e1391222e156eb1cd17;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp index 6378ba273..4bddcf1cd 100644 --- a/src/modules/m_denychans.cpp +++ b/src/modules/m_denychans.cpp @@ -1,6 +1,7 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + *. Copyright (C) 2018 Sadie Powell * Copyright (C) 2009 Daniel De Graaf * Copyright (C) 2007-2008 Robin Burchell * Copyright (C) 2007 Dennis Friis @@ -22,58 +23,125 @@ #include "inspircd.h" +enum +{ + // InspIRCd-specific. + ERR_BADCHANNEL = 926 +}; + +struct BadChannel +{ + bool allowopers; + std::string name; + std::string reason; + std::string redirect; + + BadChannel(const std::string& Name, const std::string& Redirect, const std::string& Reason, bool AllowOpers) + : allowopers(AllowOpers) + , name(Name) + , reason(Reason) + , redirect(Redirect) + { + } +}; + +typedef std::vector BadChannels; +typedef std::vector GoodChannels; + class ModuleDenyChannels : public Module { + private: + BadChannels badchannels; + GoodChannels goodchannels; + UserModeReference antiredirectmode; ChanModeReference redirectmode; public: ModuleDenyChannels() - : redirectmode(this, "redirect") + : antiredirectmode(this, "antiredirect") + , redirectmode(this, "redirect") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - /* check for redirect validity and loops/chains */ - ConfigTagList tags = ServerInstance->Config->ConfTags("badchan"); + GoodChannels goodchans; + ConfigTagList tags = ServerInstance->Config->ConfTags("goodchan"); + for (ConfigIter iter = tags.first; iter != tags.second; ++iter) + { + ConfigTag* tag = iter->second; + + // Ensure that we have the parameter. + const std::string name = tag->getString("name"); + if (name.empty()) + throw ModuleException(" is a mandatory field, at " + tag->getTagLocation()); + + goodchans.push_back(name); + } + + BadChannels badchans; + tags = ServerInstance->Config->ConfTags("badchan"); for (ConfigIter i = tags.first; i != tags.second; ++i) { - std::string name = i->second->getString("name"); - std::string redirect = i->second->getString("redirect"); + ConfigTag* tag = i->second; + + // Ensure that we have the parameter. + const std::string name = tag->getString("name"); + if (name.empty()) + throw ModuleException(" is a mandatory field, at " + tag->getTagLocation()); + + // Ensure that we have the parameter. + const std::string reason = tag->getString("reason"); + if (reason.empty()) + throw ModuleException(" is a mandatory field, at " + tag->getTagLocation()); + const std::string redirect = tag->getString("redirect"); if (!redirect.empty()) { - + // Ensure that contains a channel name. if (!ServerInstance->IsChannel(redirect)) - { - if (status.srcuser) - status.srcuser->WriteNotice("Invalid badchan redirect '" + redirect + "'"); - throw ModuleException("Invalid badchan redirect, not a channel"); - } + throw ModuleException(" is not a valid channel name, at " + tag->getTagLocation()); + + // We defer the rest of the validation of the redirect channel until we have + // finished parsing all of the badchans. + } - for (ConfigIter j = tags.first; j != tags.second; ++j) + badchans.push_back(BadChannel(name, redirect, reason, tag->getBool("allowopers"))); + } + + // Now we have all of the badchan information recorded we can check that all redirect + // channels can actually be redirected to. + for (BadChannels::const_iterator i = badchans.begin(); i != badchans.end(); ++i) + { + const BadChannel& badchan = *i; + + // If there is no redirect channel we have nothing to do. + if (badchan.redirect.empty()) + continue; + + // If the redirect channel is whitelisted then it is okay. + bool whitelisted = false; + for (GoodChannels::const_iterator j = goodchans.begin(); j != goodchans.end(); ++j) + { + if (InspIRCd::Match(badchan.redirect, *j)) { - if (InspIRCd::Match(redirect, j->second->getString("name"))) - { - bool goodchan = false; - ConfigTagList goodchans = ServerInstance->Config->ConfTags("goodchan"); - for (ConfigIter k = goodchans.first; k != goodchans.second; ++k) - { - if (InspIRCd::Match(redirect, k->second->getString("name"))) - goodchan = true; - } - - if (!goodchan) - { - /* is a badchan */ - if (status.srcuser) - status.srcuser->WriteNotice("Badchan " + name + " redirects to badchan " + redirect); - throw ModuleException("Badchan redirect loop"); - } - } + whitelisted = true; + break; } } + + if (whitelisted) + continue; + + // If the redirect channel is not blacklisted then it is okay. + for (BadChannels::const_iterator j = badchans.begin(); j != badchans.end(); ++j) + if (InspIRCd::Match(badchan.redirect, j->name)) + throw ModuleException(" cannot be a blacklisted channel name"); } + + // The config file contained no errors so we can apply the new configuration. + badchannels.swap(badchans); + goodchannels.swap(goodchans); } Version GetVersion() CXX11_OVERRIDE @@ -84,45 +152,40 @@ class ModuleDenyChannels : public Module ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - ConfigTagList tags = ServerInstance->Config->ConfTags("badchan"); - for (ConfigIter j = tags.first; j != tags.second; ++j) + for (BadChannels::const_iterator j = badchannels.begin(); j != badchannels.end(); ++j) { - if (InspIRCd::Match(cname, j->second->getString("name"))) - { - if (user->IsOper() && j->second->getBool("allowopers")) - { + const BadChannel& badchan = *j; + + // If the channel does not match the current entry we have nothing else to do. + if (!InspIRCd::Match(cname, badchan.name)) + continue; + + // If the user is an oper and opers are allowed to enter this blacklisted channel + // then allow the join. + if (user->IsOper() && badchan.allowopers) + return MOD_RES_PASSTHRU; + + // If the channel matches a whitelist then allow the join. + for (GoodChannels::const_iterator i = goodchannels.begin(); i != goodchannels.end(); ++i) + if (InspIRCd::Match(cname, *i)) return MOD_RES_PASSTHRU; - } - else - { - std::string reason = j->second->getString("reason"); - std::string redirect = j->second->getString("redirect"); - - ConfigTagList goodchans = ServerInstance->Config->ConfTags("goodchan"); - for (ConfigIter i = goodchans.first; i != goodchans.second; ++i) - { - if (InspIRCd::Match(cname, i->second->getString("name"))) - { - return MOD_RES_PASSTHRU; - } - } - - if (ServerInstance->IsChannel(redirect)) - { - /* simple way to avoid potential loops: don't redirect to +L channels */ - Channel *newchan = ServerInstance->FindChan(redirect); - if ((!newchan) || (!newchan->IsModeSet(redirectmode))) - { - user->WriteNumeric(926, "%s :Channel %s is forbidden, redirecting to %s: %s", cname.c_str(),cname.c_str(),redirect.c_str(), reason.c_str()); - Channel::JoinUser(user, redirect); - return MOD_RES_DENY; - } - } - - user->WriteNumeric(926, "%s :Channel %s is forbidden: %s", cname.c_str(),cname.c_str(),reason.c_str()); - return MOD_RES_DENY; - } + + // If there is no redirect chan, the user has enabled the antiredirect mode, or + // the target channel redirects elsewhere we just tell the user and deny the join. + Channel* target = NULL; + if (badchan.redirect.empty() || user->IsModeSet(antiredirectmode) + || ((target = ServerInstance->FindChan(badchan.redirect)) && target->IsModeSet(redirectmode))) + { + user->WriteNumeric(ERR_BADCHANNEL, cname, InspIRCd::Format("Channel %s is forbidden: %s", + cname.c_str(), badchan.reason.c_str())); + return MOD_RES_DENY; } + + // Redirect the user to the target channel. + user->WriteNumeric(ERR_BADCHANNEL, cname, InspIRCd::Format("Channel %s is forbidden, redirecting to %s: %s", + cname.c_str(), badchan.redirect.c_str(), badchan.reason.c_str())); + Channel::JoinUser(user, badchan.redirect); + return MOD_RES_DENY; } return MOD_RES_PASSTHRU; }