]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_disable.cpp
Textual improvements and fixes such as typos, casing, etc. (#1612)
[user/henk/code/inspircd.git] / src / modules / m_disable.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2019 Peter Powell <petpow@saberuk.com>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "inspircd.h"
21
22 enum
23 {
24         // From ircu.
25         ERR_DISABLED = 517
26 };
27
28 // Holds a list of disabled commands.
29 typedef std::vector<std::string> CommandList;
30
31 // Holds whether modes are disabled or not.
32 typedef std::bitset<64> ModeStatus;
33
34 class ModuleDisable : public Module
35 {
36  private:
37         CommandList commands;
38         ModeStatus chanmodes;
39         bool fakenonexistent;
40         bool notifyopers;
41         ModeStatus usermodes;
42
43         void ReadModes(ConfigTag* tag, const std::string& field, ModeType type, ModeStatus& status)
44         {
45                 const std::string modes = tag->getString(field);
46                 for (std::string::const_iterator iter = modes.begin(); iter != modes.end(); ++iter)
47                 {
48                         const char& chr = *iter;
49
50                         // Check that the character is a valid mode letter.
51                         if (!ModeParser::IsModeChar(chr))
52                                 throw ModuleException(InspIRCd::Format("Invalid mode '%c' was specified in <disabled:%s> at %s",
53                                         chr, field.c_str(), tag->getTagLocation().c_str()));
54
55                         // Check that the mode actually exists.
56                         ModeHandler* mh = ServerInstance->Modes->FindMode(chr, type);
57                         if (!chr)
58                                 throw ModuleException(InspIRCd::Format("Nonexistent mode '%c' was specified in <disabled:%s> at %s",
59                                         chr, field.c_str(), tag->getTagLocation().c_str()));
60
61                         // Disable the mode.
62                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %c (%s) %s mode has been disabled",
63                                 mh->GetModeChar(), mh->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user");
64                         status.set(chr - 'A');
65                 }
66         }
67
68         void WriteLog(const char* message, ...) CUSTOM_PRINTF(2, 3)
69         {
70                 std::string buffer;
71                 VAFORMAT(buffer, message, message);
72
73                 if (notifyopers)
74                         ServerInstance->SNO->WriteToSnoMask('a', buffer);
75                 else
76                         ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, buffer);
77         }
78
79  public:
80         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
81         {
82                 ConfigTag* tag = ServerInstance->Config->ConfValue("disabled");
83
84                 // Parse the disabled commands.
85                 CommandList newcommands;
86                 irc::spacesepstream commandlist(tag->getString("commands"));
87                 for (std::string command; commandlist.GetToken(command); )
88                 {
89                         // Check that the command actually exists.
90                         Command* handler = ServerInstance->Parser.GetHandler(command);
91                         if (!handler)
92                                 throw ModuleException(InspIRCd::Format("Nonexistent command '%s' was specified in <disabled:commands> at %s",
93                                         command.c_str(), tag->getTagLocation().c_str()));
94
95                         // Prevent admins from disabling COMMANDS and MODULES for transparency reasons.
96                         if (handler->name == "COMMANDS" || handler->name == "MODULES")
97                                 continue;
98
99                         // Disable the command.
100                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "The %s command has been disabled", handler->name.c_str());
101                         newcommands.push_back(handler->name);
102                 }
103
104                 // Parse the disabled channel modes.
105                 ModeStatus newchanmodes;
106                 ReadModes(tag, "chanmodes", MODETYPE_CHANNEL, newchanmodes);
107
108                 // Parse the disabled user modes.
109                 ModeStatus newusermodes;
110                 ReadModes(tag, "usermodes", MODETYPE_USER, newusermodes);
111
112                 // The server config was valid so we can use these now.
113                 chanmodes = newchanmodes;
114                 usermodes = newusermodes;
115                 commands.swap(newcommands);
116
117                 // Whether we should fake the non-existence of disabled things.
118                 fakenonexistent = tag->getBool("fakenonexistent", tag->getBool("fakenonexistant"));
119
120                 // Whether to notify server operators via snomask `a` about the attempted use of disabled commands/modes.
121                 notifyopers = tag->getBool("notifyopers");
122         }
123
124         ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) CXX11_OVERRIDE
125         {
126                 // If a command is unvalidated or the source is not registered we do nothing.
127                 if (!validated || user->registered != REG_ALL)
128                         return MOD_RES_PASSTHRU;
129
130                 // If the command is not disabled or the user has the servers/use-disabled-commands priv we do nothing.
131                 if (!stdalgo::isin(commands, command) || user->HasPrivPermission("servers/use-disabled-commands"))
132                         return MOD_RES_PASSTHRU;
133
134                 // The user has tried to execute a disabled command!
135                 user->CommandFloodPenalty += 2000;
136                 WriteLog("%s was blocked from executing the disabled %s command", user->GetFullRealHost().c_str(), command.c_str());
137
138                 if (fakenonexistent)
139                 {
140                         // The server administrator has specified that disabled commands should be
141                         // treated as if they do not exist.
142                         user->WriteNumeric(ERR_UNKNOWNCOMMAND, command, "Unknown command");
143                         ServerInstance->stats.Unknown++;
144                         return MOD_RES_DENY;
145                 }
146
147                 // Inform the user that the command they executed has been disabled.
148                 user->WriteNumeric(ERR_DISABLED, command, "Command disabled");
149                 return MOD_RES_DENY;
150         }
151
152         ModResult OnRawMode(User* user, Channel* chan, ModeHandler* mh, const std::string& param, bool adding) CXX11_OVERRIDE
153         {
154                 // If a mode change is remote or the source is not registered we do nothing.
155                 if (!IS_LOCAL(user) || user->registered != REG_ALL)
156                         return MOD_RES_PASSTHRU;
157
158                 // If the mode is not disabled or the user has the servers/use-disabled-modes priv we do nothing.
159                 const std::bitset<64>& disabled = (mh->GetModeType() == MODETYPE_CHANNEL) ? chanmodes : usermodes;
160                 if (!disabled.test(mh->GetModeChar() - 'A') || user->HasPrivPermission("servers/use-disabled-modes"))
161                         return MOD_RES_PASSTHRU;
162
163                 // The user has tried to change a disabled mode!
164                 const char* what = mh->GetModeType() == MODETYPE_CHANNEL ? "channel" : "user";
165                 WriteLog("%s was blocked from executing the disabled %s mode %c (%s)",
166                         user->GetFullRealHost().c_str(), what, mh->GetModeChar(), mh->name.c_str());
167
168                 if (fakenonexistent)
169                 {
170                         // The server administrator has specified that disabled modes should be
171                         // treated as if they do not exist.
172                         user->WriteNumeric(mh->GetModeType() == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK,
173                                 mh->GetModeChar(), "is an unknown mode character");
174                         return MOD_RES_DENY;
175                 }
176
177                 // Inform the user that the mode they changed has been disabled.
178                 user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c (%s) is disabled",
179                         what, mh->GetModeChar(), mh->name.c_str()));
180                 return MOD_RES_DENY;
181         }
182
183         Version GetVersion() CXX11_OVERRIDE
184         {
185                 return Version("Provides support for disabling commands and modes", VF_VENDOR);
186         }
187 };
188
189 MODULE_INIT(ModuleDisable)