From d5a6054948502625d7f0c235f6faaeea58734de5 Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Sat, 27 Jan 2018 13:05:14 +0000 Subject: [PATCH] Add ERR_INVALIDMODEPARAM for responding to invalid mode params. Currently on invalid modes we do a combination of different things: 1. Send a custom mode-specific numeric (which often collides with other modes). 2. Send a server notice. 3. Do absolutely nothing. This new numeric is a generic way of handling invalid parameters when setting a mode that avoids all of the mistakes of the previous behaviour. --- include/numeric.h | 27 ----------------- include/numericbuilder.h | 54 +++++++++++++++++++++++++++++++++ include/numerics.h | 1 + src/mode.cpp | 5 +++ src/modules/m_chanfilter.cpp | 2 +- src/modules/m_chanhistory.cpp | 13 ++++++-- src/modules/m_exemptchanops.cpp | 4 +-- src/modules/m_joinflood.cpp | 4 +-- src/modules/m_kicknorejoin.cpp | 3 ++ src/modules/m_messageflood.cpp | 4 +-- src/modules/m_nickflood.cpp | 4 +-- src/modules/m_repeat.cpp | 25 +++++++++------ 12 files changed, 98 insertions(+), 48 deletions(-) diff --git a/include/numeric.h b/include/numeric.h index 8ea2447bf..85f2f13f0 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -85,30 +85,3 @@ class Numeric::Numeric */ std::vector& GetParams() { return params; } }; - -namespace Numerics -{ - /** Builder for the ERR_NOSUCHNICK numeric. */ - class NoSuchNick : public Numeric::Numeric - { - public: - NoSuchNick(const std::string& nick) - : Numeric(ERR_NOSUCHNICK) - { - push(nick); - push("No such nick"); - } - }; - - /** Builder for the ERR_NOSUCHCHANNEL numeric. */ - class NoSuchChannel : public Numeric::Numeric - { - public: - NoSuchChannel(const std::string& chan) - : Numeric(ERR_NOSUCHCHANNEL) - { - push(chan); - push("No such channel"); - } - }; -} diff --git a/include/numericbuilder.h b/include/numericbuilder.h index 17aa9e0c8..0d55093ca 100644 --- a/include/numericbuilder.h +++ b/include/numericbuilder.h @@ -196,3 +196,57 @@ class Numeric::ParamBuilder : public GenericParamBuildername); + push(mode->GetModeChar()); + push(parameter); + push(message.empty() ? InspIRCd::Format("Invalid %s mode parameter", mode->name.c_str()) : message); + } + + InvalidModeParameter(User* user, ModeHandler* mode, const std::string& parameter, const std::string& message = "") + : Numeric(ERR_INVALIDMODEPARAM) + { + push(user->registered & REG_NICK ? user->nick : "*"); + push(mode->GetModeChar()); + push(parameter); + push(message.empty() ? InspIRCd::Format("Invalid %s mode parameter", mode->name.c_str()) : message); + } +}; + +/** Builder for the ERR_NOSUCHCHANNEL numeric. */ +class Numerics::NoSuchChannel : public Numeric::Numeric +{ + public: + NoSuchChannel(const std::string& chan) + : Numeric(ERR_NOSUCHCHANNEL) + { + push(chan); + push("No such channel"); + } +}; + +/** Builder for the ERR_NOSUCHNICK numeric. */ +class Numerics::NoSuchNick : public Numeric::Numeric +{ + public: + NoSuchNick(const std::string& nick) + : Numeric(ERR_NOSUCHNICK) + { + push(nick); + push("No such nick"); + } +}; diff --git a/include/numerics.h b/include/numerics.h index 57ecee4df..740ee1797 100644 --- a/include/numerics.h +++ b/include/numerics.h @@ -184,6 +184,7 @@ enum ERR_CANTSENDTOUSER = 531, // ??? RPL_SYNTAX = 650, // insp-specific + ERR_INVALIDMODEPARAM = 696, // insp-specific ERR_CHANOPEN = 713, ERR_KNOCKONCHAN = 714, diff --git a/src/mode.cpp b/src/mode.cpp index c07c342a3..9d17f5be8 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -89,6 +89,11 @@ void ModeHandler::DisplayEmptyList(User*, Channel*) void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel) { + const std::string message = InspIRCd::Format("You must specify a parameter for the %s mode", name.c_str()); + if (channel) + user->WriteNumeric(Numerics::InvalidModeParameter(channel, this, "*", message)); + else + user->WriteNumeric(Numerics::InvalidModeParameter(dest, this, "*", message)); } bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*) diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp index e7dc6372b..d201f5418 100644 --- a/src/modules/m_chanfilter.cpp +++ b/src/modules/m_chanfilter.cpp @@ -37,7 +37,7 @@ class ChanFilter : public ListModeBase bool ValidateParam(User* user, Channel* chan, std::string& word) CXX11_OVERRIDE { if (word.length() > 35) { - user->WriteNumeric(935, chan->name, word, "%word is too long for censor list"); + user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Word is too long for the spamfilter list")); return false; } diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index 4d74b65e0..5f081d9de 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -63,18 +63,25 @@ class HistoryMode : public ParamMode > { std::string::size_type colon = parameter.find(':'); if (colon == std::string::npos) + { + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; + } std::string duration(parameter, colon+1); if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration)))) + { + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; + } unsigned int len = ConvToInt(parameter.substr(0, colon)); unsigned int time = InspIRCd::Duration(duration); - if (len == 0) - return MODEACTION_DENY; - if (len > maxlines && IS_LOCAL(source)) + if (len == 0 || (len > maxlines && IS_LOCAL(source))) + { + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; + } if (len > maxlines) len = maxlines; diff --git a/src/modules/m_exemptchanops.cpp b/src/modules/m_exemptchanops.cpp index 52e7c4dad..b1d7b35df 100644 --- a/src/modules/m_exemptchanops.cpp +++ b/src/modules/m_exemptchanops.cpp @@ -32,7 +32,7 @@ class ExemptChanOps : public ListModeBase std::string::size_type p = word.find(':'); if (p == std::string::npos) { - user->WriteNumeric(955, chan->name, word, "Invalid exemptchanops entry, format is :"); + user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Invalid exemptchanops entry, format is :")); return false; } @@ -45,7 +45,7 @@ class ExemptChanOps : public ListModeBase if (!ServerInstance->Modes->FindMode(restriction, MODETYPE_CHANNEL)) { - user->WriteNumeric(955, chan->name, restriction, "Unknown restriction"); + user->WriteNumeric(Numerics::InvalidModeParameter(chan, this, word, "Unknown restriction")); return false; } diff --git a/src/modules/m_joinflood.cpp b/src/modules/m_joinflood.cpp index b4a8f6181..bd9e0ad9e 100644 --- a/src/modules/m_joinflood.cpp +++ b/src/modules/m_joinflood.cpp @@ -98,7 +98,7 @@ class JoinFlood : public ParamMode > std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } @@ -107,7 +107,7 @@ class JoinFlood : public ParamMode > unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); if ((njoins<1) || (nsecs<1)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index 1bc11948c..67711f766 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -95,7 +95,10 @@ class KickRejoin : public ParamMode > { int v = ConvToInt(parameter); if (v <= 0) + { + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; + } if ((IS_LOCAL(source) && ((unsigned int)v > max))) v = max; diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index 36f2c923b..0707e6ae4 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -77,7 +77,7 @@ class MsgFlood : public ParamMode > std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } @@ -88,7 +88,7 @@ class MsgFlood : public ParamMode > if ((nlines<2) || (nsecs<1)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } diff --git a/src/modules/m_nickflood.cpp b/src/modules/m_nickflood.cpp index e3b448871..50e2b3d93 100644 --- a/src/modules/m_nickflood.cpp +++ b/src/modules/m_nickflood.cpp @@ -95,7 +95,7 @@ class NickFlood : public ParamMode > std::string::size_type colon = parameter.find(':'); if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } @@ -105,7 +105,7 @@ class NickFlood : public ParamMode > if ((nnicks<1) || (nsecs<1)) { - source->WriteNumeric(608, channel->name, "Invalid flood parameter"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter)); return MODEACTION_DENY; } diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp index a57e96740..3e974c221 100644 --- a/src/modules/m_repeat.cpp +++ b/src/modules/m_repeat.cpp @@ -140,18 +140,20 @@ class RepeatMode : public ParamMode > ChannelSettings settings; if (!ParseSettings(source, parameter, settings)) { - source->WriteNotice("*** Invalid syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, + "Invalid repeat syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}.")); return MODEACTION_DENY; } if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog)) { - source->WriteNotice("*** You can't set needed lines higher than backlog"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, + "Invalid repeat syntax. You can't set needed lines higher than backlog.")); return MODEACTION_DENY; } LocalUser* localsource = IS_LOCAL(source); - if ((localsource) && (!ValidateSettings(localsource, settings))) + if ((localsource) && (!ValidateSettings(localsource, channel, parameter, settings))) return MODEACTION_DENY; ext.set(channel, settings); @@ -302,11 +304,12 @@ class RepeatMode : public ParamMode > return true; } - bool ValidateSettings(LocalUser* source, const ChannelSettings& settings) + bool ValidateSettings(LocalUser* source, Channel* channel, const std::string& parameter, const ChannelSettings& settings) { if (settings.Backlog && !ms.MaxBacklog) { - source->WriteNotice("*** The server administrator has disabled backlog matching"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, + "Invalid repeat parameter. The server administrator has disabled backlog matching.")); return false; } @@ -315,21 +318,25 @@ class RepeatMode : public ParamMode > if (settings.Diff > ms.MaxDiff) { if (ms.MaxDiff == 0) - source->WriteNotice("*** The server administrator has disabled matching on edit distance"); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, + "Invalid repeat parameter. The server administrator has disabled matching on edit distance.")); else - source->WriteNotice("*** The distance you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxDiff)); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( + "Invalid repeat parameter. The distance you specified is too great. Maximum allowed is %u.", ms.MaxDiff))); return false; } if (ms.MaxLines && settings.Lines > ms.MaxLines) { - source->WriteNotice("*** The line number you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxLines)); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( + "Invalid repeat parameter. The line number you specified is too great. Maximum allowed is %u.", ms.MaxLines))); return false; } if (ms.MaxSecs && settings.Seconds > ms.MaxSecs) { - source->WriteNotice("*** The seconds you specified is too great. Maximum allowed is " + ConvToStr(ms.MaxSecs)); + source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( + "Invalid repeat parameter. The seconds you specified is too great. Maximum allowed is %u.", ms.MaxSecs))); return false; } } -- 2.39.5