diff options
-rw-r--r-- | include/mode.h | 10 | ||||
-rw-r--r-- | src/mode.cpp | 28 |
2 files changed, 26 insertions, 12 deletions
diff --git a/include/mode.h b/include/mode.h index 3877e0d3b..3d8f0c940 100644 --- a/include/mode.h +++ b/include/mode.h @@ -601,7 +601,15 @@ class CoreExport ModeParser : public fakederef<ModeParser> * and not send it to other servers. The mode change will be processed * locally and sent to local user(s) as usual. */ - MODE_LOCALONLY = 2 + MODE_LOCALONLY = 2, + + /** If this flag is set then the mode change will be subject to access checks. + * For more information see the documentation of the PrefixMode class, + * ModeHandler::levelrequired and ModeHandler::AccessCheck(). + * Modules may explicitly allow a mode change regardless of this flag by returning + * MOD_RES_ALLOW from the OnPreMode hook. Only affects channel mode changes. + */ + MODE_CHECKACCESS = 4 }; ModeParser(); diff --git a/src/mode.cpp b/src/mode.cpp index ec0cb6985..4fac34f78 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -388,17 +388,23 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModResult MOD_RESULT; FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters)); - bool SkipAccessChecks = false; - - if (!IS_LOCAL(user) || MOD_RESULT == MOD_RES_ALLOW) - SkipAccessChecks = true; - else if (MOD_RESULT == MOD_RES_DENY) - return; - - if (targetuser && !SkipAccessChecks && user != targetuser) + if (IS_LOCAL(user)) { - user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users"); - return; + if (MOD_RESULT == MOD_RES_PASSTHRU) + { + if ((targetuser) && (user != targetuser)) + { + // Local users may only change the modes of other users if a module explicitly allows it + user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users"); + return; + } + + // This is a mode change by a local user and modules didn't explicitly allow/deny. + // Ensure access checks will happen for each mode being changed. + flags |= MODE_CHECKACCESS; + } + else if (MOD_RESULT == MOD_RES_DENY) + return; // Entire mode change denied by a module } const std::string& mode_sequence = parameters[1]; @@ -450,7 +456,7 @@ void ModeParser::Process(const std::vector<std::string>& parameters, User* user, } } - ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks); + ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, (!(flags & MODE_CHECKACCESS))); if (ma != MODEACTION_ALLOW) continue; |