summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mode.h10
-rw-r--r--src/mode.cpp28
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;