]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_user/umode_s.cpp
Fix not rejecting attempts to set snomasks with SAMODE/override.
[user/henk/code/inspircd.git] / src / coremods / core_user / umode_s.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017, 2020 Sadie Powell <sadie@witchery.services>
5  *   Copyright (C) 2013, 2016 Attila Molnar <attilamolnar@hush.com>
6  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
7  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
8  *   Copyright (C) 2008, 2010 Craig Edwards <brain@inspircd.org>
9  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
10  *   Copyright (C) 2006 Robin Burchell <robin+git@viroteck.net>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25
26 #include "inspircd.h"
27 #include "core_user.h"
28
29 ModeUserServerNoticeMask::ModeUserServerNoticeMask(Module* Creator)
30         : ModeHandler(Creator, "snomask", 's', PARAM_SETONLY, MODETYPE_USER)
31 {
32         oper = true;
33         syntax = "(+|-)<snomasks>|*";
34 }
35
36 ModeAction ModeUserServerNoticeMask::OnModeChange(User* source, User* dest, Channel*, std::string &parameter, bool adding)
37 {
38         if (adding)
39         {
40                 dest->SetMode(this, true);
41                 // Process the parameter (remove chars we don't understand, remove redundant chars, etc.)
42                 parameter = ProcessNoticeMasks(dest, parameter);
43                 return MODEACTION_ALLOW;
44         }
45         else
46         {
47                 if (dest->IsModeSet(this))
48                 {
49                         dest->SetMode(this, false);
50                         dest->snomasks.reset();
51                         return MODEACTION_ALLOW;
52                 }
53         }
54
55         // Mode not set and trying to unset, deny
56         return MODEACTION_DENY;
57 }
58
59 std::string ModeUserServerNoticeMask::GetUserParameter(const User* user) const
60 {
61         std::string ret;
62         if (!user->IsModeSet(this))
63                 return ret;
64
65         ret.push_back('+');
66         for (unsigned char n = 0; n < 64; n++)
67         {
68                 if (user->snomasks[n])
69                         ret.push_back(n + 'A');
70         }
71         return ret;
72 }
73
74 std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::string& input)
75 {
76         bool adding = true;
77         std::bitset<64> curr = user->snomasks;
78
79         for (std::string::const_iterator i = input.begin(); i != input.end(); ++i)
80         {
81                 switch (*i)
82                 {
83                         case '+':
84                                 adding = true;
85                         break;
86                         case '-':
87                                 adding = false;
88                         break;
89                         case '*':
90                                 for (size_t j = 0; j < 64; j++)
91                                 {
92                                         const char chr = j + 'A';
93                                         if (user->HasSnomaskPermission(chr) && ServerInstance->SNO->IsSnomaskUsable(chr))
94                                                 curr[j] = adding;
95                                 }
96                         break;
97                         default:
98                                 // For local users check whether the given snomask is valid and enabled - IsSnomaskUsable() tests both.
99                                 // For remote users accept what we were told, unless the snomask char is not a letter.
100                                 if (IS_LOCAL(user))
101                                 {
102                                         if (!ServerInstance->SNO->IsSnomaskUsable(*i))
103                                         {
104                                                 user->WriteNumeric(ERR_UNKNOWNSNOMASK, *i, "is an unknown snomask character");
105                                                 continue;
106                                         }
107                                         else if (!user->IsOper())
108                                         {
109                                                 user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may %sset snomask %c",
110                                                         adding ? "" : "un", *i));
111                                                 continue;
112
113                                         }
114                                         else if (!user->HasSnomaskPermission(*i))
115                                         {
116                                                 user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to snomask %c",
117                                                         user->oper->name.c_str(), *i));
118                                                 continue;
119                                         }
120                                 }
121                                 else if (!(((*i >= 'a') && (*i <= 'z')) || ((*i >= 'A') && (*i <= 'Z'))))
122                                         continue;
123
124                                 size_t index = ((*i) - 'A');
125                                 curr[index] = adding;
126                         break;
127                 }
128         }
129
130         std::string plus = "+";
131         std::string minus = "-";
132
133         // Apply changes and construct two strings consisting of the newly added and the removed snomask chars
134         for (size_t i = 0; i < 64; i++)
135         {
136                 bool isset = curr[i];
137                 if (user->snomasks[i] != isset)
138                 {
139                         user->snomasks[i] = isset;
140                         std::string& appendhere = (isset ? plus : minus);
141                         appendhere.push_back(i+'A');
142                 }
143         }
144
145         // Create the final string that will be shown to the user and sent to servers
146         // Form: "+ABc-de"
147         std::string output;
148         if (plus.length() > 1)
149                 output = plus;
150
151         if (minus.length() > 1)
152                 output += minus;
153
154         // Unset the snomask usermode itself if every snomask was unset
155         if (user->snomasks.none())
156                 user->SetMode(this, false);
157
158         return output;
159 }