summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorPeter Powell <petpow@saberuk.com>2019-01-24 15:10:02 +0000
committerPeter Powell <petpow@saberuk.com>2019-01-24 15:10:02 +0000
commit4047a143fc1d16350db70c94b9ea77d79de05714 (patch)
tree854169605c3b134d5edc39067d0298f7d1e9c64b /src/modules
parentcbef0241a04eafe5250b75ebb3f7ef8c32ecb260 (diff)
Move the <disabled> tag out of the core to a new module.
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/m_conn_umodes.cpp6
-rw-r--r--src/modules/m_disable.cpp189
-rw-r--r--src/modules/m_samode.cpp3
3 files changed, 192 insertions, 6 deletions
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);
}