diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/command_parse.cpp | 19 | ||||
-rw-r--r-- | src/configreader.cpp | 46 | ||||
-rw-r--r-- | src/inspircd.cpp | 1 | ||||
-rw-r--r-- | src/mode.cpp | 11 | ||||
-rw-r--r-- | src/modules/m_conn_umodes.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_disable.cpp | 189 | ||||
-rw-r--r-- | src/modules/m_samode.cpp | 3 |
7 files changed, 192 insertions, 83 deletions
diff --git a/src/command_parse.cpp b/src/command_parse.cpp index c2ae39d49..7a732f8b5 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -266,24 +266,6 @@ void CommandParser::ProcessCommand(LocalUser* user, std::string& command, Comman } } - if ((user->registered == REG_ALL) && (!user->IsOper()) && (handler->IsDisabled())) - { - /* command is disabled! */ - user->CommandFloodPenalty += failpenalty; - if (ServerInstance->Config->DisabledDontExist) - { - user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command"); - } - else - { - user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "This command has been disabled."); - } - - ServerInstance->SNO->WriteToSnoMask('a', "%s denied for %s (%s@%s)", - command.c_str(), user->nick.c_str(), user->ident.c_str(), user->GetRealHost().c_str()); - return; - } - if ((!command_p.empty()) && (command_p.back().empty()) && (!handler->allow_empty_last_param)) command_p.pop_back(); @@ -333,7 +315,6 @@ CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpa , min_params(minpara) , max_params(maxpara) , use_count(0) - , disabled(false) , works_before_reg(false) , allow_empty_last_param(true) , Penalty(1) diff --git a/src/configreader.cpp b/src/configreader.cpp index ce03f1d9e..5a0ceff06 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -72,31 +72,6 @@ ServerConfig::~ServerConfig() delete EmptyTag; } -bool ServerConfig::ApplyDisabledCommands() -{ - // Enable everything first. - const CommandParser::CommandMap& commands = ServerInstance->Parser.GetCommands(); - for (CommandParser::CommandMap::const_iterator x = commands.begin(); x != commands.end(); ++x) - x->second->Disable(false); - - // Now disable the commands specified in the config. - std::string command; - irc::spacesepstream commandlist(ConfValue("disabled")->getString("commands")); - while (commandlist.GetToken(command)) - { - Command* handler = ServerInstance->Parser.GetHandler(command); - if (!handler) - { - ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Unable to disable the %s command as it does not exist!", command.c_str()); - continue; - } - - ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "The %s command has been disabled", command.c_str()); - handler->Disable(true); - } - return true; -} - static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make) { ConfigTagList tags = conf->ConfTags(tag); @@ -378,7 +353,6 @@ void ServerConfig::Fill() ServerDesc = server->getString("description", "Configure Me"); Network = server->getString("network", "Network"); NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534); - DisabledDontExist = ConfValue("disabled")->getBool("fakenonexistant"); CustomVersion = security->getString("customversion"); HideBans = security->getBool("hidebans"); HideServer = security->getString("hideserver", security->getString("hidewhois")); @@ -429,25 +403,6 @@ void ServerConfig::Fill() RestrictBannedUsers = ServerConfig::BUT_RESTRICT_NOTIFY; else throw CoreException(restrictbannedusers + " is an invalid <options:restrictbannedusers> value, at " + options->getTagLocation()); - - DisabledUModes.reset(); - std::string modes = ConfValue("disabled")->getString("usermodes"); - for (std::string::const_iterator p = modes.begin(); p != modes.end(); ++p) - { - // Complain when the character is not a valid mode character. - if (!ModeParser::IsModeChar(*p)) - throw CoreException("Invalid usermode " + std::string(1, *p) + " was found."); - DisabledUModes.set(*p - 'A'); - } - - DisabledCModes.reset(); - modes = ConfValue("disabled")->getString("chanmodes"); - for (std::string::const_iterator p = modes.begin(); p != modes.end(); ++p) - { - if (!ModeParser::IsModeChar(*p)) - throw CoreException("Invalid chanmode " + std::string(1, *p) + " was found."); - DisabledCModes.set(*p - 'A'); - } } // WARNING: it is not safe to use most of the codebase in this function, as it @@ -723,7 +678,6 @@ void ConfigReaderThread::Finish() ServerInstance->Users.RehashCloneCounts(); ServerInstance->XLines->CheckELines(); ServerInstance->XLines->ApplyLines(); - Config->ApplyDisabledCommands(); User* user = ServerInstance->FindNick(TheUserUID); ConfigStatus status(user); diff --git a/src/inspircd.cpp b/src/inspircd.cpp index 7e299700b..09e48ea1f 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -442,7 +442,6 @@ InspIRCd::InspIRCd(int argc, char** argv) : // Build ISupport as ModuleManager::LoadAll() does not do it this->ISupport.Build(); - Config->ApplyDisabledCommands(); if (!pl.empty()) { diff --git a/src/mode.cpp b/src/mode.cpp index 5793b4e66..459eb21c8 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -312,17 +312,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode } } - if (IS_LOCAL(user) && !user->IsOper()) - { - const std::bitset<64>& disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes; - if (disabled.test(modechar - 'A')) - { - user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c has been locked by the administrator", - type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); - return MODEACTION_DENY; - } - } - if ((adding) && (IS_LOCAL(user)) && (mh->NeedsOper()) && (!user->HasModePermission(mh))) { /* It's an oper only mode, and they don't have access to it. */ diff --git a/src/modules/m_conn_umodes.cpp b/src/modules/m_conn_umodes.cpp index 1f2fe7455..3132aed40 100644 --- a/src/modules/m_conn_umodes.cpp +++ b/src/modules/m_conn_umodes.cpp @@ -38,10 +38,6 @@ class ModuleModesOnConnect : public Module void OnUserConnect(LocalUser* user) CXX11_OVERRIDE { - // Backup and zero out the disabled usermodes, so that we can override them here. - const std::bitset<64> save = ServerInstance->Config->DisabledUModes; - ServerInstance->Config->DisabledUModes.reset(); - ConfigTag* tag = user->MyClass->config; std::string ThisModes = tag->getString("modes"); if (!ThisModes.empty()) @@ -58,8 +54,6 @@ class ModuleModesOnConnect : public Module ServerInstance->Parser.CallHandler("MODE", modes, user); } - - ServerInstance->Config->DisabledUModes = save; } }; diff --git a/src/modules/m_disable.cpp b/src/modules/m_disable.cpp new file mode 100644 index 000000000..203f9ee64 --- /dev/null +++ b/src/modules/m_disable.cpp @@ -0,0 +1,189 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" + +enum +{ + // From ircu. + ERR_DISABLED = 517 +}; + +// Holds a list of disabled commands. +typedef std::vector<std::string> CommandList; + +// Holds whether modes are disabled or not. +typedef std::bitset<64> ModeStatus; + +class ModuleDisable : public Module +{ + private: + CommandList commands; + ModeStatus chanmodes; + bool fakenonexistent; + bool notifyopers; + ModeStatus usermodes; + + void ReadModes(ConfigTag* tag, const std::string& field, ModeType type, ModeStatus& status) + { + const std::string modes = tag->getString(field); + for (std::string::const_iterator iter = modes.begin(); iter != modes.end(); ++iter) + { + const char& chr = *iter; + + // Check that the character is a valid mode letter. + if (!ModeParser::IsModeChar(chr)) + throw ModuleException(InspIRCd::Format("Invalid mode '%c' was specified in <disabled:%s> at %s", + chr, field.c_str(), tag->getTagLocation().c_str())); + + // Check that the mode actually exists. + ModeHandler* mh = ServerInstance->Modes->FindMode(chr, type); + if (!chr) + throw ModuleException(InspIRCd::Format("Non-existent mode '%c' was specified in <disabled:%s> at %s", + chr, field.c_str(), tag->getTagLocation().c_str())); + + // Disable the mode. + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %c (%s) %s mode has been disabled", + mh->GetModeChar(), mh->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user"); + status.set(chr - 'A'); + } + } + + void WriteLog(const char* message, ...) CUSTOM_PRINTF(2, 3) + { + std::string buffer; + VAFORMAT(buffer, message, message); + + if (notifyopers) + ServerInstance->SNO->WriteToSnoMask('a', buffer); + else + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, buffer); + } + + public: + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE + { + ConfigTag* tag = ServerInstance->Config->ConfValue("disabled"); + + // Parse the disabled commands. + CommandList newcommands; + irc::spacesepstream commandlist(tag->getString("commands")); + for (std::string command; commandlist.GetToken(command); ) + { + // Check that the command actually exists. + Command* handler = ServerInstance->Parser.GetHandler(command); + if (!handler) + throw ModuleException(InspIRCd::Format("Non-existent command '%s' was specified in <disabled:commands> at %s", + command.c_str(), tag->getTagLocation().c_str())); + + // Prevent admins from disabling COMMANDS and MODULES for transparency reasons. + if (handler->name == "COMMANDS" || handler->name == "MODULES") + continue; + + // Disable the command. + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %s command has been disabled", handler->name.c_str()); + newcommands.push_back(handler->name); + } + + // Parse the disabled channel modes. + ModeStatus newchanmodes; + ReadModes(tag, "chanmodes", MODETYPE_CHANNEL, newchanmodes); + + // Parse the disabled user modes. + ModeStatus newusermodes; + ReadModes(tag, "usermodes", MODETYPE_USER, newusermodes); + + // The server config was valid so we can use these now. + chanmodes = newchanmodes; + usermodes = newusermodes; + commands.swap(newcommands); + + // Whether we should fake the non-existence of disabled things. + fakenonexistent = tag->getBool("fakenonexistent", tag->getBool("fakenonexistant")); + + // Whether to notify server operators via snomask `a` about the attempted use of disabled commands/modes. + notifyopers = tag->getBool("notifyopers"); + } + + ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE + { + // If a command is unvalidated or the source is not registered we do nothing. + if (!validated || user->registered != REG_ALL) + return MOD_RES_PASSTHRU; + + // If the command is not disabled or the user has the servers/use-disabled-commands priv we do nothing. + if (!stdalgo::isin(commands, command) || user->HasPrivPermission("servers/use-disabled-commands")) + return MOD_RES_PASSTHRU; + + // The user has tried to execute a disabled command! + user->CommandFloodPenalty += 2000; + WriteLog("%s was blocked from executing the disabled %s command", user->GetFullRealHost().c_str(), command.c_str()); + + if (fakenonexistent) + { + // The server administrator has specified that disabled commands should be + // treated as if they do not exist. + user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command"); + ServerInstance->stats.Unknown++; + return MOD_RES_DENY; + } + + // Inform the user that the command they executed has been disabled. + user->WriteNumeric(ERR_DISABLED, command, "Command disabled"); + return MOD_RES_DENY; + } + + ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE + { + // If a mode change is remote or the source is not registered we do nothing. + if (!IS_LOCAL(user) || user->registered != REG_ALL) + return MOD_RES_PASSTHRU; + + // If the mode is not disabled or the user has the servers/use-disabled-modes priv we do nothing. + const std::bitset<64>& disabled = (mh->GetModeType() == MODETYPE_CHANNEL) ? chanmodes : usermodes; + if (!disabled.test(mh->GetModeChar() - 'A') || user->HasPrivPermission("servers/use-disabled-modes")) + return MOD_RES_PASSTHRU; + + // The user has tried to change a disabled mode! + const char* what = mh->GetModeType() == MODETYPE_CHANNEL ? "channel" : "user"; + WriteLog("%s was blocked from executing the disabled %s mode %c (%s)", + user->GetFullRealHost().c_str(), what, mh->GetModeChar(), mh->name.c_str()); + + if (fakenonexistent) + { + // The server administrator has specified that disabled modes should be + // treated as if they do not exist. + user->WriteNumeric(mh->GetModeType() == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, + mh->GetModeChar(), "is unknown mode char to me"); + return MOD_RES_DENY; + } + + // Inform the user that the mode they changed has been disabled. + user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c (%s) is disabled", + what, mh->GetModeChar(), mh->name.c_str())); + return MOD_RES_DENY; + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Provides support for disabling commands and modes", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleDisable) diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 8f28a7e9c..db3345b98 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -124,6 +124,9 @@ class ModuleSaMode : public Module void Prioritize() CXX11_OVERRIDE { + Module* disabled = ServerInstance->Modules->Find("m_disabled.so"); + ServerInstance->Modules->SetPriority(this, I_OnRawMode, PRIORITY_BEFORE, disabled); + Module *override = ServerInstance->Modules->Find("m_override.so"); ServerInstance->Modules->SetPriority(this, I_OnPreMode, PRIORITY_BEFORE, override); } |