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