X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_denychans.cpp;h=04962558c027a70d55c8b9932aa81ca2b9aecef6;hb=e2b0f3dc9ef4d56c71d7abda13e6139ca092e387;hp=b09ee7977d24d65a199db45debaef82bc988be7a;hpb=5c9427cde0a949a17a476311db0a2a275345337b;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp index b09ee7977..04962558c 100644 --- a/src/modules/m_denychans.cpp +++ b/src/modules/m_denychans.cpp @@ -1,10 +1,15 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2019 Matt Schatz + * Copyright (C) 2013, 2018 Sadie Powell + * Copyright (C) 2012-2013 Attila Molnar + * Copyright (C) 2012 Robby + * Copyright (C) 2009 Uli Schlachter * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007-2008 Robin Burchell + * Copyright (C) 2008 Robin Burchell * Copyright (C) 2007 Dennis Friis - * Copyright (C) 2005 Craig Edwards + * Copyright (C) 2005, 2007, 2010 Craig Edwards * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -22,108 +27,169 @@ #include "inspircd.h" -/* $ModDesc: Implements config tags which allow blocking of joins to channels */ +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: - void init() CXX11_OVERRIDE + ModuleDenyChannels() + : antiredirectmode(this, "antiredirect") + , redirectmode(this, "redirect") { - Implementation eventlist[] = { I_OnUserPreJoin, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); } - void OnRehash(User* user) CXX11_OVERRIDE + 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 (user) - user->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("badchan"); - 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 (user) - user->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 { - return Version("Implements config tags which allow blocking of joins to channels", VF_VENDOR); + return Version("Allows the server administrator to prevent users from joining channels matching a glob.", VF_VENDOR); } 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('L')))) - { - user->WriteNumeric(926, "%s %s :Channel %s is forbidden, redirecting to %s: %s",user->nick.c_str(),cname.c_str(),cname.c_str(),redirect.c_str(), reason.c_str()); - Channel::JoinUser(user, redirect); - return MOD_RES_DENY; - } - } - - user->WriteNumeric(926, "%s %s :Channel %s is forbidden: %s",user->nick.c_str(),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; }