X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_denychans.cpp;h=4bddcf1cda30c3f13801c4da25e19d38683f8dfc;hb=56375392ba94f2552bbeeeab4fd39e1e50295525;hp=14c7166e6bd1157955645dcbf14f4c4106068dc6;hpb=4b0f6c610f755e0cb93843d5a2a6c70336eafe39;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_denychans.cpp b/src/modules/m_denychans.cpp index 14c7166e6..4bddcf1cd 100644 --- a/src/modules/m_denychans.cpp +++ b/src/modules/m_denychans.cpp @@ -1,110 +1,194 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev. - * E-mail: - * - * - * - * Written by Craig Edwards, Craig McLure, and others. - * This program is free but copyrighted software; see - * the file COPYING for details. + *. Copyright (C) 2018 Sadie Powell + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2007-2008 Robin Burchell + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2005 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 + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ -#include "users.h" -#include "channels.h" -#include "modules.h" -#include "hashcomp.h" #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: - - - ConfigReader *Conf; + BadChannels badchannels; + GoodChannels goodchannels; + UserModeReference antiredirectmode; + ChanModeReference redirectmode; public: - ModuleDenyChannels(InspIRCd* Me) : Module::Module(Me) - { - - Conf = new ConfigReader(ServerInstance); - } - - virtual void OnRehash(const std::string ¶m) - { - DELETE(Conf); - Conf = new ConfigReader(ServerInstance); - } - - virtual ~ModuleDenyChannels() + ModuleDenyChannels() + : antiredirectmode(this, "antiredirect") + , redirectmode(this, "redirect") { - DELETE(Conf); - } - - virtual Version GetVersion() - { - return Version(1,0,0,1,VF_VENDOR,API_VERSION); } - void Implements(char* List) + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - List[I_OnUserPreJoin] = List[I_OnRehash] = 1; - } + GoodChannels goodchans; + ConfigTagList tags = ServerInstance->Config->ConfTags("goodchan"); + for (ConfigIter iter = tags.first; iter != tags.second; ++iter) + { + ConfigTag* tag = iter->second; - virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) - { - for (int j =0; j < Conf->Enumerate("badchan"); j++) + // 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) { - irc::string cn = Conf->ReadValue("badchan","name",j).c_str(); - irc::string thischan = cname; - if (thischan == cn) + 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()) { - if ((Conf->ReadFlag("badchan","allowopers",j)) && *user->oper) - { - return 0; - } - else + // Ensure that contains a channel name. + if (!ServerInstance->IsChannel(redirect)) + 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. + } + + 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)) { - std::string reason = Conf->ReadValue("badchan","reason",j); - user->WriteServ("926 %s %s :Channel %s is forbidden: %s",user->nick,cname,cname,reason.c_str()); - return 1; + whitelisted = true; + break; } } - } - return 0; - } -}; -// stuff down here is the module-factory stuff. For basic modules you can ignore this. + if (whitelisted) + continue; -class ModuleDenyChannelsFactory : public ModuleFactory -{ - public: - ModuleDenyChannelsFactory() - { + // 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); } - - ~ModuleDenyChannelsFactory() + + Version GetVersion() CXX11_OVERRIDE { + return Version("Implements config tags which allow blocking of joins to channels", VF_VENDOR); } - - virtual Module * CreateModule(InspIRCd* Me) + + + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE { - return new ModuleDenyChannels(Me); - } - -}; + for (BadChannels::const_iterator j = badchannels.begin(); j != badchannels.end(); ++j) + { + 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; -extern "C" void * init_module( void ) -{ - return new ModuleDenyChannelsFactory; -} + // 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; + + // 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; + } +}; +MODULE_INIT(ModuleDenyChannels)