From 59d2dab8a1849b289dc7304e51e290b70bc3a528 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 19 Feb 2020 05:12:53 +0000 Subject: Convert some things to HasFd that were previously missed. --- src/listensocket.cpp | 3 +-- src/modules/m_ident.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/listensocket.cpp b/src/listensocket.cpp index cb1c5c73f..8c5fda59a 100644 --- a/src/listensocket.cpp +++ b/src/listensocket.cpp @@ -48,8 +48,7 @@ ListenSocket::ListenSocket(ConfigTag* tag, const irc::sockets::sockaddrs& bind_t } fd = socket(bind_to.family(), SOCK_STREAM, 0); - - if (this->fd == -1) + if (!HasFd()) return; #ifdef IPV6_V6ONLY diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp index dea411cea..15e46b83a 100644 --- a/src/modules/m_ident.cpp +++ b/src/modules/m_ident.cpp @@ -113,8 +113,7 @@ class IdentRequestSocket : public EventHandler age = ServerInstance->Time(); SetFd(socket(user->server_sa.family(), SOCK_STREAM, 0)); - - if (GetFd() == -1) + if (!HasFd()) throw ModuleException("Could not create socket"); done = false; -- cgit v1.3.1-10-gc9f91 From a3df29ba4902da2dd0e2dea1c8a9469ced629804 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 19 Feb 2020 08:24:40 +0000 Subject: Extract time skip warning code to a static function. --- src/inspircd.cpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/inspircd.cpp b/src/inspircd.cpp index e2d3f8dff..4d4c9a6ea 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -135,6 +135,21 @@ namespace #endif } + // Checks whether the server clock has skipped too much and warn about it if it has. + void CheckTimeSkip(time_t oldtime, time_t newtime) + { + if (!ServerInstance->Config->TimeSkipWarn) + return; + + time_t timediff = oldtime - newtime; + + if (timediff > ServerInstance->Config->TimeSkipWarn) + ServerInstance->SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped forwards by %lu seconds!", timediff); + + else if (timediff < -ServerInstance->Config->TimeSkipWarn) + ServerInstance->SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped backwards by %lu seconds!", labs(timediff)); + } + // Drops to the unprivileged user/group specified in . void DropRoot() { @@ -667,17 +682,7 @@ void InspIRCd::Run() if (TIME.tv_sec != OLDTIME) { CollectStats(); - - if (Config->TimeSkipWarn) - { - time_t timediff = TIME.tv_sec - OLDTIME; - - if (timediff > Config->TimeSkipWarn) - SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped forwards by %lu seconds!", timediff); - - else if (timediff < -Config->TimeSkipWarn) - SNO->WriteToSnoMask('a', "\002Performance warning!\002 Server clock jumped backwards by %lu seconds!", labs(timediff)); - } + CheckTimeSkip(OLDTIME, TIME.tv_sec); OLDTIME = TIME.tv_sec; -- cgit v1.3.1-10-gc9f91 From 327bacd3687f307a5f8586856a94b16c9e4370bf Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 19 Feb 2020 09:58:47 +0000 Subject: Lower to 5m to prevent misconfigs denying access. --- docs/conf/modules.conf.example | 5 +++-- src/modules/m_ircv3_sts.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index ae32bb0e0..ad2b9ca8a 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1224,14 +1224,15 @@ # # host - A glob match for the SNI hostname to apply this policy to. # duration - The amount of time that the policy lasts for. Defaults to -# approximately two months by default. +# five minutes by default. You should raise this to a month +# or two once you know that your config is valid. # port - The port on which TLS connections to the server are being # accepted. You MUST have a CA-verified certificate on this # port. Self signed certificates are not acceptable. # preload - Whether client developers can include your certificate in # preload lists. # -# +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Join flood module: Adds support for join flood protection +j X:Y. diff --git a/src/modules/m_ircv3_sts.cpp b/src/modules/m_ircv3_sts.cpp index 86ea159c1..4d2839062 100644 --- a/src/modules/m_ircv3_sts.cpp +++ b/src/modules/m_ircv3_sts.cpp @@ -171,7 +171,7 @@ class ModuleIRCv3STS : public Module if (!HasValidSSLPort(port)) throw ModuleException(" must be a TLS port, at " + tag->getTagLocation()); - unsigned long duration = tag->getDuration("duration", 60*60*24*30*2); + unsigned long duration = tag->getDuration("duration", 5*60, 60); bool preload = tag->getBool("preload"); cap.SetPolicy(host, duration, port, preload); -- cgit v1.3.1-10-gc9f91 From 89f36a6f1c13465cebe56ee1e12fec1dec40679a Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 19 Feb 2020 18:00:36 +0000 Subject: Fix a memory leak in the httpd module when sockets are closed late. --- src/modules/m_httpd.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index bdb1d50fc..978a60ab7 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -95,7 +95,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru { if (!messagecomplete) { - AddToCull(); + Close(); return false; } @@ -229,7 +229,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru // IOHook may have errored if (!getError().empty()) { - AddToCull(); + Close(); return; } } @@ -244,9 +244,19 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru sockets.erase(this); } + void Close() CXX11_OVERRIDE + { + if (waitingcull || !HasFd()) + return; + + waitingcull = true; + BufferedSocket::Close(); + ServerInstance->GlobalCulls.AddItem(this); + } + void OnError(BufferedSocketError) CXX11_OVERRIDE { - AddToCull(); + Close(); } void SendHTTPError(unsigned int response) @@ -315,7 +325,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru { SendHeaders(s.length(), response, *hheaders); WriteData(s); - Close(true); + BufferedSocket::Close(true); } void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders) @@ -323,16 +333,6 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru Page(n->str(), response, hheaders); } - void AddToCull() - { - if (waitingcull) - return; - - waitingcull = true; - Close(); - ServerInstance->GlobalCulls.AddItem(this); - } - bool ParseURI(const std::string& uristr, HTTPRequestURI& out) { http_parser_url_init(&url); @@ -439,7 +439,7 @@ class ModuleHttpServer : public Module for (insp::intrusive_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) { HttpServerSocket* sock = *i; - sock->AddToCull(); + sock->Close(); } return Module::cull(); } -- cgit v1.3.1-10-gc9f91 From 82c89d40cc6cd0100b4c68e72f869ff007f4ef36 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 20 Feb 2020 18:02:51 +0000 Subject: Add support for using environment variables in the config. --- src/configparser.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/configparser.cpp b/src/configparser.cpp index 0102c910c..6fdc56c32 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -205,7 +205,7 @@ struct Parser while (1) { ch = next(); - if (isalnum(ch) || (varname.empty() && ch == '#')) + if (isalnum(ch) || (varname.empty() && ch == '#') || ch == '.') varname.push_back(ch); else if (ch == ';') break; @@ -233,6 +233,13 @@ struct Parser throw CoreException("Invalid numeric character reference '&" + varname + ";'"); value.push_back(static_cast(lvalue)); } + else if (varname.compare(0, 4, "env.") == 0) + { + const char* envstr = getenv(varname.c_str() + 4); + if (!envstr) + throw CoreException("Undefined XML environment entity reference '&" + varname + ";'"); + value.append(envstr); + } else { insp::flat_map::iterator var = stack.vars.find(varname); -- cgit v1.3.1-10-gc9f91 From 77a2f04c41410a0e9780d048134bc57f66990c9f Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 21 Feb 2020 20:26:23 +0000 Subject: Improve the documentation of . --- docs/conf/modules.conf.example | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index ad2b9ca8a..9f8c46d05 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1947,11 +1947,10 @@ # Layer via AUTHENTICATE. Note: You also need to have cap loaded # for SASL to work. # -# Define the following to your services server name to improve security -# by ensuring the SASL messages are only sent to the services server -# and not to all connected servers. This prevents a rogue server from -# capturing SASL messages and disables the SASL cap when services is -# down. + +# You must define to the name of your services server so +# that InspIRCd knows where to send SASL authentication messages and +# when it should enable the SASL capability. # #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -- cgit v1.3.1-10-gc9f91 From b31a4aea1b68f9fd27d4bf30440948056af2edce Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 21 Feb 2020 20:27:05 +0000 Subject: Add support for requiring users to use SSL in order to use SASL. --- docs/conf/modules.conf.example | 5 ++++- src/modules/m_sasl.cpp | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 9f8c46d05..1b26182e4 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1951,7 +1951,10 @@ # You must define to the name of your services server so # that InspIRCd knows where to send SASL authentication messages and # when it should enable the SASL capability. -# +# You can also define to require users to use SSL in +# order to be able to use SASL. +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Secure list module: Prevent /LIST in the first minute of connection, diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp index 9fe270567..19b2c9f50 100644 --- a/src/modules/m_sasl.cpp +++ b/src/modules/m_sasl.cpp @@ -109,11 +109,16 @@ class ServerTracker class SASLCap : public Cap::Capability { + private: std::string mechlist; const ServerTracker& servertracker; + UserCertificateAPI sslapi; bool OnRequest(LocalUser* user, bool adding) CXX11_OVERRIDE { + if (requiressl && sslapi && !sslapi->GetCertificate(user)) + return false; + // Servers MUST NAK any sasl capability request if the authentication layer // is unavailable. return servertracker.IsOnline(); @@ -121,6 +126,9 @@ class SASLCap : public Cap::Capability bool OnList(LocalUser* user) CXX11_OVERRIDE { + if (requiressl && sslapi && !sslapi->GetCertificate(user)) + return false; + // Servers MUST NOT advertise the sasl capability if the authentication layer // is unavailable. return servertracker.IsOnline(); @@ -132,9 +140,11 @@ class SASLCap : public Cap::Capability } public: + bool requiressl; SASLCap(Module* mod, const ServerTracker& tracker) : Cap::Capability(mod, "sasl") , servertracker(tracker) + , sslapi(mod) { } @@ -426,10 +436,13 @@ class ModuleSASL : public Module void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - std::string target = ServerInstance->Config->ConfValue("sasl")->getString("target"); + ConfigTag* tag = ServerInstance->Config->ConfValue("sasl"); + + const std::string target = tag->getString("target"); if (target.empty()) throw ModuleException(" must be set to the name of your services server!"); + cap.requiressl = tag->getBool("requiressl"); sasl_target = target; servertracker.Reset(); } -- cgit v1.3.1-10-gc9f91 From e861d5bfca1c33d1e6fb1464d318943b32a56062 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 21 Feb 2020 20:37:00 +0000 Subject: Use "yes" instead of "true" in the example configs. --- docs/conf/inspircd.conf.example | 2 +- docs/conf/modules.conf.example | 6 +++--- include/server.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index dbd56d2fe..317fdb117 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -732,7 +732,7 @@ # Turning this option off will make the server spend more time on users we may # potentially not want. Normally this should be neglible, though. # Default value is true - clonesonconnect="true" + clonesonconnect="yes" # timeskipwarn: The time period that a server clock can jump by before # operators will be warned that the server is having performance issues. diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 1b26182e4..8d1ee8074 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1597,7 +1597,7 @@ # # # enableumode - If enabled, user mode +O is required for override. # # # -# +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper levels module: Gives each oper a level and prevents actions @@ -1693,7 +1693,7 @@ # 'saveperiod' determines how often to check if the database needs to be # saved to disk. Defaults to every five seconds. # # # @@ -1804,7 +1804,7 @@ # nokicks (+Q) mode is set. Defaults to false. # protectedrank: Members having this rank or above may not be /REMOVE'd # by anyone. Set to 0 to disable this feature. Defaults to 50000. -# +# #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Repeat module: Allows to block, kick or ban upon similar messages diff --git a/include/server.h b/include/server.h index 51756b469..078f9662f 100644 --- a/include/server.h +++ b/include/server.h @@ -40,7 +40,7 @@ class CoreExport Server : public classbase */ bool uline; - /** True if this server is a silent uline, i.e. silent="true" in the uline block + /** True if this server is a silent uline, i.e. silent="yes" in the uline block */ bool silentuline; -- cgit v1.3.1-10-gc9f91 From d05695e5cbc1d2843bf1603e71fc2003117deb3a Mon Sep 17 00:00:00 2001 From: Matt Schatz Date: Tue, 25 Feb 2020 22:11:50 -0700 Subject: Improve the description of the sslinfo module (#1755). --- src/modules/m_sslinfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 7f58da46a..1b63b89cf 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -215,7 +215,7 @@ class ModuleSSLInfo Version GetVersion() CXX11_OVERRIDE { - return Version("SSL Certificate Utilities", VF_VENDOR); + return Version("Provides user SSL information and certificate utilities", VF_VENDOR); } void OnWhois(Whois::Context& whois) CXX11_OVERRIDE -- cgit v1.3.1-10-gc9f91 From 9a0046a709e1fe9236d54838e2de530813972400 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 24 Feb 2020 02:10:36 +0000 Subject: Allow modules to prevent a message from updating the idle time. --- include/message.h | 4 ++++ include/modules/ctctags.h | 4 ++++ src/coremods/core_message.cpp | 2 +- src/modules/m_ircv3_ctctags.cpp | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/message.h b/include/message.h index 3a7c7018e..eae27ff94 100644 --- a/include/message.h +++ b/include/message.h @@ -39,6 +39,9 @@ class CoreExport MessageDetails /* Whether to send the original message back to clients with echo-message support. */ bool echo_original; + /** Whether to update the source user's idle time. */ + bool update_idle; + /** The users who are exempted from receiving this message. */ CUList exemptions; @@ -78,6 +81,7 @@ class CoreExport MessageDetails MessageDetails(MessageType mt, const std::string& msg, const ClientProtocol::TagMap& tags) : echo(true) , echo_original(false) + , update_idle(true) , original_text(msg) , tags_in(tags) , text(msg) diff --git a/include/modules/ctctags.h b/include/modules/ctctags.h index f1af43c09..ad45d12b1 100644 --- a/include/modules/ctctags.h +++ b/include/modules/ctctags.h @@ -85,6 +85,9 @@ class CTCTags::TagMessageDetails /* Whether to send the original tags back to clients with echo-message support. */ bool echo_original; + /** Whether to update the source user's idle time. */ + bool update_idle; + /** The users who are exempted from receiving this message. */ CUList exemptions; @@ -97,6 +100,7 @@ class CTCTags::TagMessageDetails TagMessageDetails(const ClientProtocol::TagMap& tags) : echo(true) , echo_original(false) + , update_idle(true) , tags_in(tags) { } diff --git a/src/coremods/core_message.cpp b/src/coremods/core_message.cpp index 648172b57..1093aad67 100644 --- a/src/coremods/core_message.cpp +++ b/src/coremods/core_message.cpp @@ -128,7 +128,7 @@ namespace { // If the source is local and was not sending a CTCP reply then update their idle time. LocalUser* lsource = IS_LOCAL(source); - if (lsource && (msgdetails.type != MSG_NOTICE || !msgdetails.IsCTCP())) + if (lsource && msgdetails.update_idle && (msgdetails.type != MSG_NOTICE || !msgdetails.IsCTCP())) lsource->idle_lastmsg = ServerInstance->Time(); // Inform modules that a message was sent. diff --git a/src/modules/m_ircv3_ctctags.cpp b/src/modules/m_ircv3_ctctags.cpp index 421bf89c3..1bb803bc2 100644 --- a/src/modules/m_ircv3_ctctags.cpp +++ b/src/modules/m_ircv3_ctctags.cpp @@ -57,7 +57,7 @@ class CommandTagMsg : public Command { // If the source is local then update its idle time. LocalUser* lsource = IS_LOCAL(source); - if (lsource) + if (lsource && msgdetails.update_idle) lsource->idle_lastmsg = ServerInstance->Time(); // Inform modules that a TAGMSG was sent. -- cgit v1.3.1-10-gc9f91 From 1899ce4e2151dd1ea5741df106ba1e71c63eb0b2 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 27 Feb 2020 11:01:32 +0000 Subject: Move user command stuff from CommandBase to Command. --- include/ctables.h | 43 +++++++++++++++---------------------------- src/command_parse.cpp | 10 +++++----- 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/include/ctables.h b/include/ctables.h index 938deac15..4e3d196e6 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -148,10 +148,6 @@ class CoreExport CommandBase : public ServiceProvider const ClientProtocol::TagMap& GetTags() const { return tags; } }; - /** User flags needed to execute the command or 0 - */ - unsigned char flags_needed; - /** Minimum number of parameters command takes */ const unsigned int min_params; @@ -162,14 +158,6 @@ class CoreExport CommandBase : public ServiceProvider */ const unsigned int max_params; - /** used by /stats m - */ - unsigned long use_count; - - /** True if the command can be issued before registering - */ - bool works_before_reg; - /** True if the command allows an empty last parameter. * When false and the last parameter is empty, it's popped BEFORE * checking there are enough params, etc. (i.e. the handler won't @@ -179,20 +167,11 @@ class CoreExport CommandBase : public ServiceProvider */ bool allow_empty_last_param; - /** Syntax string for the command, displayed if non-empty string. - * This takes place of the text in the 'not enough parameters' numeric. - */ - std::string syntax; - /** Translation type list for possible parameters, used to tokenize * parameters into UIDs and SIDs etc. */ std::vector translation; - /** How many seconds worth of penalty does this command have? - */ - unsigned int Penalty; - /** Create a new command. * @param me The module which created this command. * @param cmd Command name. This must be UPPER CASE. @@ -211,24 +190,32 @@ class CoreExport CommandBase : public ServiceProvider */ virtual void EncodeParameter(std::string& parameter, unsigned int index); - /** @return true if the command works before registration. - */ - bool WorksBeforeReg() - { - return works_before_reg; - } - virtual ~CommandBase(); }; class CoreExport Command : public CommandBase { public: + /** The user modes required to be able to execute this command. */ + unsigned char flags_needed; + /** If true, the command will not be forwarded by the linking module even if it comes via ENCAP. * Can be used to forward commands before their effects. */ bool force_manual_route; + /** The number of seconds worth of penalty that executing this command gives. */ + unsigned int Penalty; + + /** The number of times this command has been executed. */ + unsigned long use_count; + + /** If non-empty then the syntax of the parameter for this command. */ + std::string syntax; + + /** Whether the command can be issued before registering. */ + bool works_before_reg; + Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); /** Handle the command from a user. diff --git a/src/command_parse.cpp b/src/command_parse.cpp index 0405a5659..f8c88a9f0 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -290,7 +290,7 @@ void CommandParser::ProcessCommand(LocalUser* user, std::string& command, Comman return; } - if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg())) + if ((user->registered != REG_ALL) && (!handler->works_before_reg)) { user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOTREGISTERED, command, "You have not registered"); @@ -327,13 +327,9 @@ void CommandParser::RemoveCommand(Command* x) CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : ServiceProvider(mod, cmd, SERVICE_COMMAND) - , flags_needed(0) , min_params(minpara) , max_params(maxpara) - , use_count(0) - , works_before_reg(false) , allow_empty_last_param(true) - , Penalty(1) { } @@ -352,7 +348,11 @@ RouteDescriptor CommandBase::GetRouting(User* user, const Params& parameters) Command::Command(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : CommandBase(mod, cmd, minpara, maxpara) + , flags_needed(0) , force_manual_route(false) + , Penalty(1) + , use_count(0) + , works_before_reg(false) { } -- cgit v1.3.1-10-gc9f91 From 600ea3b38fde78c8105f94c39772dea8043f0573 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 27 Feb 2020 11:50:30 +0000 Subject: Clean up the documentation of the Command and SplitCommand classes. --- include/ctables.h | 64 +++++++++++++++++++++++++++++++++++++++++-------------- src/commands.cpp | 5 +++++ 2 files changed, 53 insertions(+), 16 deletions(-) diff --git a/include/ctables.h b/include/ctables.h index 4e3d196e6..a3fcdfbd4 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -195,13 +195,23 @@ class CoreExport CommandBase : public ServiceProvider class CoreExport Command : public CommandBase { + protected: + /** Initializes a new instance of the Command class. + * @param me The module which created this instance. + * @param cmd The name of the command. + * @param minpara The minimum number of parameters that the command accepts. + * @param maxpara The maximum number of parameters that the command accepts. + */ + Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); + public: + /** Unregisters this command from the command parser. */ + ~Command() CXX11_OVERRIDE; + /** The user modes required to be able to execute this command. */ unsigned char flags_needed; - /** If true, the command will not be forwarded by the linking module even if it comes via ENCAP. - * Can be used to forward commands before their effects. - */ + /** Whether the command will not be forwarded by the linking module even if it comes via ENCAP. */ bool force_manual_route; /** The number of seconds worth of penalty that executing this command gives. */ @@ -216,33 +226,55 @@ class CoreExport Command : public CommandBase /** Whether the command can be issued before registering. */ bool works_before_reg; - Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); - /** Handle the command from a user. - * @param parameters The parameters for the command. * @param user The user who issued the command. - * @return Return CMD_SUCCESS on success, or CMD_FAILURE on failure. + * @param parameters The parameters for the command. + * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID + * if the command was malformed. */ virtual CmdResult Handle(User* user, const Params& parameters) = 0; - /** Register this object in the CommandParser - */ + /** Registers this command with the command parser. */ void RegisterService() CXX11_OVERRIDE; - - /** Destructor - * Removes this command from the command parser - */ - ~Command(); }; class CoreExport SplitCommand : public Command { +protected: + /** Initializes a new instance of the SplitCommand class. + * @param me The module which created this instance. + * @param cmd The name of the command. + * @param minpara The minimum number of parameters that the command accepts. + * @param maxpara The maximum number of parameters that the command accepts. + */ + SplitCommand(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0); + public: - SplitCommand(Module* me, const std::string &cmd, unsigned int minpara = 0, unsigned int maxpara = 0) - : Command(me, cmd, minpara, maxpara) {} + /** @copydoc Commmand::Handle */ CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; + + /** Handle the command from a local user. + * @param user The user who issued the command. + * @param parameters The parameters for the command. + * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID + * if the command was malformed. + */ virtual CmdResult HandleLocal(LocalUser* user, const Params& parameters); + + /** Handle the command from a remote user. + * @param user The user who issued the command. + * @param parameters The parameters for the command. + * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID + * if the command was malformed. + */ virtual CmdResult HandleRemote(RemoteUser* user, const Params& parameters); + + /** Handle the command from a server user. + * @param user The user who issued the command. + * @param parameters The parameters for the command. + * @return Returns CMD_FAILURE on failure, CMD_SUCCESS on success, or CMD_INVALID + * if the command was malformed. + */ virtual CmdResult HandleServer(FakeUser* user, const Params& parameters); }; diff --git a/src/commands.cpp b/src/commands.cpp index d4f380272..9215a4db5 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -24,6 +24,11 @@ #include "inspircd.h" +SplitCommand::SplitCommand(Module* me, const std::string& cmd, unsigned int minpara, unsigned int maxpara) + : Command(me, cmd, minpara, maxpara) +{ +} + CmdResult SplitCommand::Handle(User* user, const Params& parameters) { switch (user->usertype) -- cgit v1.3.1-10-gc9f91 From 8d1255a82c1bdb53928a007be113caff15683d53 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 27 Feb 2020 12:16:25 +0000 Subject: Move command stuff to a more appropriate source file. --- src/command_parse.cpp | 42 ------------------------------------------ src/commands.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/command_parse.cpp b/src/command_parse.cpp index f8c88a9f0..11d3cf15b 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -325,48 +325,6 @@ void CommandParser::RemoveCommand(Command* x) cmdlist.erase(n); } -CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) - : ServiceProvider(mod, cmd, SERVICE_COMMAND) - , min_params(minpara) - , max_params(maxpara) - , allow_empty_last_param(true) -{ -} - -CommandBase::~CommandBase() -{ -} - -void CommandBase::EncodeParameter(std::string& parameter, unsigned int index) -{ -} - -RouteDescriptor CommandBase::GetRouting(User* user, const Params& parameters) -{ - return ROUTE_LOCALONLY; -} - -Command::Command(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) - : CommandBase(mod, cmd, minpara, maxpara) - , flags_needed(0) - , force_manual_route(false) - , Penalty(1) - , use_count(0) - , works_before_reg(false) -{ -} - -Command::~Command() -{ - ServerInstance->Parser.RemoveCommand(this); -} - -void Command::RegisterService() -{ - if (!ServerInstance->Parser.AddCommand(this)) - throw ModuleException("Command already exists: " + name); -} - void CommandParser::ProcessBuffer(LocalUser* user, const std::string& buffer) { ClientProtocol::ParseOutput parseoutput; diff --git a/src/commands.cpp b/src/commands.cpp index 9215a4db5..8343cfaac 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -24,6 +24,49 @@ #include "inspircd.h" +CommandBase::CommandBase(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) + : ServiceProvider(mod, cmd, SERVICE_COMMAND) + , min_params(minpara) + , max_params(maxpara) + , allow_empty_last_param(true) +{ +} + +CommandBase::~CommandBase() +{ +} + +void CommandBase::EncodeParameter(std::string& parameter, unsigned int index) +{ +} + +RouteDescriptor CommandBase::GetRouting(User* user, const Params& parameters) +{ + return ROUTE_LOCALONLY; +} + +Command::Command(Module* mod, const std::string& cmd, unsigned int minpara, unsigned int maxpara) + : CommandBase(mod, cmd, minpara, maxpara) + , flags_needed(0) + , force_manual_route(false) + , Penalty(1) + , use_count(0) + , works_before_reg(false) +{ +} + +Command::~Command() +{ + ServerInstance->Parser.RemoveCommand(this); +} + +void Command::RegisterService() +{ + if (!ServerInstance->Parser.AddCommand(this)) + throw ModuleException("Command already exists: " + name); +} + + SplitCommand::SplitCommand(Module* me, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : Command(me, cmd, minpara, maxpara) { -- cgit v1.3.1-10-gc9f91 From 5c01f7c08f223ebfa671a9f36ac1fd8203880c9e Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 27 Feb 2020 18:52:00 +0000 Subject: Standardise the characters allowed in config identifiers. --- src/configparser.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/configparser.cpp b/src/configparser.cpp index 6fdc56c32..4748fa847 100644 --- a/src/configparser.cpp +++ b/src/configparser.cpp @@ -158,12 +158,20 @@ struct Parser } } + bool wordchar(char ch) + { + return isalnum(ch) + || ch == '-' + || ch == '.' + || ch == '_'; + } + void nextword(std::string& rv) { int ch = next(); while (isspace(ch)) ch = next(); - while (isalnum(ch) || ch == '_'|| ch == '-') + while (wordchar(ch)) { rv.push_back(ch); ch = next(); @@ -205,7 +213,7 @@ struct Parser while (1) { ch = next(); - if (isalnum(ch) || (varname.empty() && ch == '#') || ch == '.') + if (wordchar(ch) || (varname.empty() && ch == '#')) varname.push_back(ch); else if (ch == ';') break; -- cgit v1.3.1-10-gc9f91 From 5960cbcde3ad216b4e69ab3ded57568b738333c0 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 9 Mar 2020 03:44:41 +0000 Subject: Fix get_cpu_count not being evaluated as a scalar. This fixes a bug where the changes in 0c34d28447 did not work. --- configure | 2 +- tools/test-build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index fb87c3dd9..ccb551ce5 100755 --- a/configure +++ b/configure @@ -431,7 +431,7 @@ print_format <<"EOM"; <|GREEN Execution User:|> $config{USER} ($config{UID}) <|GREEN Socket Engine:|> $config{SOCKETENGINE} -To build with these settings run '<|GREEN make -j${\get_cpu_count + 1} install|>' now. +To build with these settings run '<|GREEN make -j${\(get_cpu_count() + 1)} install|>' now. EOM diff --git a/tools/test-build b/tools/test-build index 516af0866..25981d4a6 100755 --- a/tools/test-build +++ b/tools/test-build @@ -64,7 +64,7 @@ foreach my $compiler (@compilers) { say "Failed to configure using the $compiler compiler and the $socketengine socket engine!"; exit 1; } - if (execute 'make', '--jobs', get_cpu_count + 1, 'install') { + if (execute 'make', '--jobs', get_cpu_count() + 1, 'install') { say "Failed to compile using the $compiler compiler and the $socketengine socket engine!"; exit 1; } -- cgit v1.3.1-10-gc9f91 From 32abc31869290e22292e0b051c4fafc0bb36f43f Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 9 Mar 2020 04:34:11 +0000 Subject: Fix being case sensitive. --- src/modules/m_sslinfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index 1b63b89cf..f0bfbb424 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -314,7 +314,8 @@ class ModuleSSLInfo { ssl_cert* cert = cmd.sslapi.GetCertificate(user); bool ok = true; - if (myclass->config->getString("requiressl") == "trusted") + const std::string requiressl = myclass->config->getString("requiressl"); + if (stdalgo::string::equalsci(requiressl, "trusted")) { ok = (cert && cert->IsCAVerified()); ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Class requires a trusted SSL cert. Client %s one.", (ok ? "has" : "does not have")); -- cgit v1.3.1-10-gc9f91 From bfefabfb0f2636445e7dfb91e14bf80d079e44e4 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 9 Mar 2020 13:44:07 +0000 Subject: Implement support for multi-line CAP responses. --- src/modules/m_cap.cpp | 85 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp index f1248e2cd..3e07a86e7 100644 --- a/src/modules/m_cap.cpp +++ b/src/modules/m_cap.cpp @@ -255,7 +255,7 @@ class Cap::ManagerImpl : public Cap::Manager, public ReloadModule::EventListener return true; } - void HandleList(std::string& out, LocalUser* user, bool show_all, bool show_values, bool minus_prefix = false) const + void HandleList(std::vector& out, LocalUser* user, bool show_all, bool show_values, bool minus_prefix = false) const { Ext show_caps = (show_all ? ~0 : capext.get(user)); @@ -268,24 +268,25 @@ class Cap::ManagerImpl : public Cap::Manager, public ReloadModule::EventListener if ((show_all) && (!cap->OnList(user))) continue; + std::string token; if (minus_prefix) - out.push_back('-'); - out.append(cap->GetName()); + token.push_back('-'); + token.append(cap->GetName()); if (show_values) { const std::string* capvalue = cap->GetValue(user); if ((capvalue) && (!capvalue->empty()) && (capvalue->find(' ') == std::string::npos)) { - out.push_back('='); - out.append(*capvalue, 0, MAX_VALUE_LENGTH); + token.push_back('='); + token.append(*capvalue, 0, MAX_VALUE_LENGTH); } } - out.push_back(' '); + out.push_back(token); } } - void HandleClear(LocalUser* user, std::string& result) + void HandleClear(LocalUser* user, std::vector& result) { HandleList(result, user, false, false, true); capext.unset(user); @@ -302,22 +303,26 @@ namespace return std::string(); // List requested caps - std::string ret; - managerimpl->HandleList(ret, user, false, false); + std::vector result; + managerimpl->HandleList(result, user, false, false); - // Serialize cap protocol version. If building a human-readable string append a new token, otherwise append only a single character indicating the version. - Cap::Protocol protocol = managerimpl->GetProtocol(user); + // Serialize cap protocol version. If building a human-readable string append a + // new token, otherwise append only a single character indicating the version. + std::string version; if (human) - ret.append("capversion=3."); - else if (!ret.empty()) - ret.erase(ret.length()-1); - - if (protocol == Cap::CAP_302) - ret.push_back('2'); - else - ret.push_back('1'); + version.append("capversion=3."); + switch (managerimpl->GetProtocol(user)) + { + case Cap::CAP_302: + version.push_back('2'); + break; + default: + version.push_back('1'); + break; + } + result.push_back(version); - return ret; + return stdalgo::string::join(result, ' '); } } @@ -355,30 +360,46 @@ void Cap::ExtItem::FromInternal(Extensible* container, const std::string& value) class CapMessage : public Cap::MessageBase { public: - CapMessage(LocalUser* user, const std::string& subcmd, const std::string& result) + CapMessage(LocalUser* user, const std::string& subcmd, const std::string& result, bool asterisk) : Cap::MessageBase(subcmd) { SetUser(user); + if (asterisk) + PushParam("*"); PushParamRef(result); } }; class CommandCap : public SplitCommand { + private: Events::ModuleEventProvider evprov; Cap::ManagerImpl manager; ClientProtocol::EventProvider protoevprov; - void DisplayResult(LocalUser* user, const std::string& subcmd, std::string& result) + void DisplayResult(LocalUser* user, const std::string& subcmd, std::vector result, bool asterisk) { - if (*result.rbegin() == ' ') - result.erase(result.end()-1); - DisplayResult2(user, subcmd, result); + size_t maxline = ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->ServerName.size() - user->nick.length() - subcmd.length() - 11; + std::string line; + for (std::vector::const_iterator iter = result.begin(); iter != result.end(); ++iter) + { + if (line.length() + iter->length() < maxline) + { + line.append(*iter); + line.push_back(' '); + } + else + { + DisplaySingleResult(user, subcmd, line, asterisk); + line.clear(); + } + } + DisplaySingleResult(user, subcmd, line, false); } - void DisplayResult2(LocalUser* user, const std::string& subcmd, const std::string& result) + void DisplaySingleResult(LocalUser* user, const std::string& subcmd, const std::string& result, bool asterisk) { - CapMessage msg(user, subcmd, result); + CapMessage msg(user, subcmd, result, asterisk); ClientProtocol::Event ev(protoevprov, msg); user->Send(ev); } @@ -408,7 +429,7 @@ class CommandCap : public SplitCommand return CMD_FAILURE; const std::string replysubcmd = (manager.HandleReq(user, parameters[1]) ? "ACK" : "NAK"); - DisplayResult2(user, replysubcmd, parameters[1]); + DisplaySingleResult(user, replysubcmd, parameters[1], false); } else if (irc::equals(subcommand, "END")) { @@ -428,16 +449,16 @@ class CommandCap : public SplitCommand } } - std::string result; + std::vector result; // Show values only if supports v3.2 and doing LS manager.HandleList(result, user, is_ls, ((is_ls) && (capversion != Cap::CAP_LEGACY))); - DisplayResult(user, subcommand, result); + DisplayResult(user, subcommand, result, (capversion != Cap::CAP_LEGACY)); } else if (irc::equals(subcommand, "CLEAR") && (manager.GetProtocol(user) == Cap::CAP_LEGACY)) { - std::string result; + std::vector result; manager.HandleClear(user, result); - DisplayResult(user, "ACK", result); + DisplayResult(user, "ACK", result, false); } else { -- cgit v1.3.1-10-gc9f91 From 0643ce085c6a946fa52f2aa603f9f68d7a33a778 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 9 Mar 2020 13:57:06 +0000 Subject: Fix not assigning bits to capabilities correctly. This makes it correctly throw when the capability limit is reached and allows up to 64 capabilities to be created instead of 32. --- src/modules/m_cap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp index 3e07a86e7..b91e9ead2 100644 --- a/src/modules/m_cap.cpp +++ b/src/modules/m_cap.cpp @@ -78,9 +78,9 @@ class Cap::ManagerImpl : public Cap::Manager, public ReloadModule::EventListener used |= cap->GetMask(); } - for (unsigned int i = 0; i < MAX_CAPS; i++) + for (size_t i = 0; i < MAX_CAPS; i++) { - Capability::Bit bit = (1 << i); + Capability::Bit bit = (static_cast(1) << i); if (!(used & bit)) return bit; } -- cgit v1.3.1-10-gc9f91 From feaceb2b037123c8687b3afdd80b2ffba61a5652 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Mon, 9 Mar 2020 22:50:48 +0000 Subject: Fix unnecessary inlining in command handler constructors. --- src/coremods/core_loadmodule.cpp | 8 +++++++- src/modules/m_check.cpp | 3 ++- src/modules/m_cycle.cpp | 3 ++- src/modules/m_globalload.cpp | 3 ++- src/modules/m_globops.cpp | 3 ++- src/modules/m_ojoin.cpp | 3 ++- src/modules/m_opermotd.cpp | 3 ++- src/modules/m_sajoin.cpp | 3 ++- src/modules/m_sakick.cpp | 3 ++- src/modules/m_samode.cpp | 3 ++- src/modules/m_sanick.cpp | 3 ++- src/modules/m_sapart.cpp | 3 ++- src/modules/m_saquit.cpp | 3 ++- src/modules/m_satopic.cpp | 3 ++- src/modules/m_sethost.cpp | 3 ++- src/modules/m_setident.cpp | 3 ++- src/modules/m_setidle.cpp | 3 ++- src/modules/m_swhois.cpp | 3 ++- 18 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/coremods/core_loadmodule.cpp b/src/coremods/core_loadmodule.cpp index a725d4322..6a54b6d1e 100644 --- a/src/coremods/core_loadmodule.cpp +++ b/src/coremods/core_loadmodule.cpp @@ -33,7 +33,13 @@ class CommandLoadmodule : public Command public: /** Constructor for loadmodule. */ - CommandLoadmodule ( Module* parent) : Command(parent,"LOADMODULE",1,1) { flags_needed='o'; syntax = ""; } + CommandLoadmodule(Module* parent) + : Command(parent,"LOADMODULE", 1, 1) + { + flags_needed = 'o'; + syntax = ""; + } + /** Handle command. * @param parameters The parameters to the command * @param user The user issuing the command diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index 25d85b6be..f74ddb922 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -150,7 +150,8 @@ class CommandCheck : public Command : Command(parent,"CHECK", 1) , snomaskmode(parent, "snomask") { - flags_needed = 'o'; syntax = "||| []"; + flags_needed = 'o'; + syntax = "||| []"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index ca8d8a374..50d233dc0 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -36,7 +36,8 @@ class CommandCycle : public SplitCommand CommandCycle(Module* Creator) : SplitCommand(Creator, "CYCLE", 1) { - Penalty = 3; syntax = " [:]"; + Penalty = 3; + syntax = " [:]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index 0f3d0c27f..cb7d6b5fd 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -124,7 +124,8 @@ class CommandGreloadmodule : public Command public: CommandGreloadmodule(Module* Creator) : Command(Creator, "GRELOADMODULE", 1) { - flags_needed = 'o'; syntax = " []"; + flags_needed = 'o'; + syntax = " []"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp index 3ef26cec7..8b165424e 100644 --- a/src/modules/m_globops.cpp +++ b/src/modules/m_globops.cpp @@ -35,7 +35,8 @@ class CommandGlobops : public Command public: CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1) { - flags_needed = 'o'; syntax = ":"; + flags_needed = 'o'; + syntax = ":"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp index 3f7197ed0..150f3558e 100644 --- a/src/modules/m_ojoin.cpp +++ b/src/modules/m_ojoin.cpp @@ -37,7 +37,8 @@ class CommandOjoin : public SplitCommand : SplitCommand(parent, "OJOIN", 1) , npmh(&mode) { - flags_needed = 'o'; syntax = ""; + flags_needed = 'o'; + syntax = ""; active = false; } diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp index 11bfc36c1..36998a4b3 100644 --- a/src/modules/m_opermotd.cpp +++ b/src/modules/m_opermotd.cpp @@ -45,7 +45,8 @@ class CommandOpermotd : public Command CommandOpermotd(Module* Creator) : Command(Creator,"OPERMOTD", 0, 1) { - flags_needed = 'o'; syntax = "[]"; + flags_needed = 'o'; + syntax = "[]"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp index 559cdf6be..b329543e4 100644 --- a/src/modules/m_sajoin.cpp +++ b/src/modules/m_sajoin.cpp @@ -35,7 +35,8 @@ class CommandSajoin : public Command CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "[] [,]+"; + flags_needed = 'o'; + syntax = "[] [,]+"; TRANSLATE2(TR_NICK, TR_TEXT); } diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp index 5669a6370..4cc26fecc 100644 --- a/src/modules/m_sakick.cpp +++ b/src/modules/m_sakick.cpp @@ -31,7 +31,8 @@ class CommandSakick : public Command public: CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3) { - flags_needed = 'o'; syntax = " [:]"; + flags_needed = 'o'; + syntax = " [:]"; TRANSLATE3(TR_TEXT, TR_NICK, TR_TEXT); } diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index de7b4fd22..be14022a1 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -37,7 +37,8 @@ class CommandSamode : public Command CommandSamode(Module* Creator) : Command(Creator,"SAMODE", 2) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = " (+|-) []"; + flags_needed = 'o'; + syntax = " (+|-) []"; active = false; } diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp index 8689778a2..6f760cf0b 100644 --- a/src/modules/m_sanick.cpp +++ b/src/modules/m_sanick.cpp @@ -33,7 +33,8 @@ class CommandSanick : public Command CommandSanick(Module* Creator) : Command(Creator,"SANICK", 2) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = " "; + flags_needed = 'o'; + syntax = " "; TRANSLATE2(TR_NICK, TR_TEXT); } diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 1ffffaa15..7a922cfb9 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -32,7 +32,8 @@ class CommandSapart : public Command public: CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3) { - flags_needed = 'o'; syntax = " [,]+ [:]"; + flags_needed = 'o'; + syntax = " [,]+ [:]"; TRANSLATE3(TR_NICK, TR_TEXT, TR_TEXT); } diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp index aad840b8e..d0743ec5d 100644 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@ -34,7 +34,8 @@ class CommandSaquit : public Command public: CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2) { - flags_needed = 'o'; syntax = " :"; + flags_needed = 'o'; + syntax = " :"; TRANSLATE2(TR_NICK, TR_TEXT); } diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp index 25b343f5b..6e718df5e 100644 --- a/src/modules/m_satopic.cpp +++ b/src/modules/m_satopic.cpp @@ -33,7 +33,8 @@ class CommandSATopic : public Command public: CommandSATopic(Module* Creator) : Command(Creator,"SATOPIC", 2, 2) { - flags_needed = 'o'; syntax = " :"; + flags_needed = 'o'; + syntax = " :"; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp index 3e61ff3d2..2bacded6f 100644 --- a/src/modules/m_sethost.cpp +++ b/src/modules/m_sethost.cpp @@ -36,7 +36,8 @@ class CommandSethost : public Command : Command(Creator,"SETHOST", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = ""; + flags_needed = 'o'; + syntax = ""; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp index 85e148a85..079564b23 100644 --- a/src/modules/m_setident.cpp +++ b/src/modules/m_setident.cpp @@ -34,7 +34,8 @@ class CommandSetident : public Command CommandSetident(Module* Creator) : Command(Creator,"SETIDENT", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = ""; + flags_needed = 'o'; + syntax = ""; } CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_setidle.cpp b/src/modules/m_setidle.cpp index f9d8b3319..531aaf875 100644 --- a/src/modules/m_setidle.cpp +++ b/src/modules/m_setidle.cpp @@ -41,7 +41,8 @@ class CommandSetidle : public SplitCommand public: CommandSetidle(Module* Creator) : SplitCommand(Creator,"SETIDLE", 1) { - flags_needed = 'o'; syntax = ""; + flags_needed = 'o'; + syntax = ""; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp index 0d0f0d14e..091fbf937 100644 --- a/src/modules/m_swhois.cpp +++ b/src/modules/m_swhois.cpp @@ -44,7 +44,8 @@ class CommandSwhois : public Command , operblock("swhois_operblock", ExtensionItem::EXT_USER, Creator) , swhois("swhois", ExtensionItem::EXT_USER, Creator) { - flags_needed = 'o'; syntax = " :"; + flags_needed = 'o'; + syntax = " :"; TRANSLATE2(TR_NICK, TR_TEXT); } -- cgit v1.3.1-10-gc9f91 From 55882c39f1025e29674c42741ee1e00ec8c2169e Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 11 Mar 2020 13:58:45 +0000 Subject: Fix detection of the "plaintext" pseudo-hash being case sensitive. --- src/command_parse.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command_parse.cpp b/src/command_parse.cpp index 11d3cf15b..c4e55c3ca 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -39,7 +39,7 @@ bool InspIRCd::PassCompare(Extensible* ex, const std::string& data, const std::s return false; /* We dont handle any hash types except for plaintext - Thanks tra26 */ - if (!hashtype.empty() && hashtype != "plaintext") + if (!hashtype.empty() && !stdalgo::string::equalsci(hashtype, "plaintext")) return false; return TimingSafeCompare(data, input); -- cgit v1.3.1-10-gc9f91 From 0a67b8861adfca7b09e59d9639e26b6bf71859a5 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 11 Mar 2020 14:32:46 +0000 Subject: Warn if the server config contains an unhashed password. This will be made a hard failure in v4. --- include/users.h | 6 ++++++ src/configreader.cpp | 8 ++++++++ src/modules/m_cgiirc.cpp | 9 ++++++++- src/modules/m_customtitle.cpp | 8 +++++++- src/modules/m_vhost.cpp | 10 +++++++++- src/users.cpp | 6 ++++-- 6 files changed, 42 insertions(+), 5 deletions(-) diff --git a/include/users.h b/include/users.h index ca9c3f557..c08be8c6f 100644 --- a/include/users.h +++ b/include/users.h @@ -149,6 +149,12 @@ struct CoreExport ConnectClass : public refcountbase */ insp::flat_set ports; + /** If non-empty then the password a user must specify in PASS to be assigned to this class. */ + std::string password; + + /** If non-empty then the hash algorithm that the password field is hashed with. */ + std::string passwordhash; + /** Create a new connect class with no settings. */ ConnectClass(ConfigTag* tag, char type, const std::string& mask); diff --git a/src/configreader.cpp b/src/configreader.cpp index 51f846f70..a43a9d78c 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -304,6 +304,14 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn); me->limit = tag->getUInt("limit", me->limit); me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames); + me->password = tag->getString("password", me->password); + + me->passwordhash = tag->getString("hash", me->passwordhash); + if (!me->password.empty() && (me->passwordhash.empty() || stdalgo::string::equalsci(me->passwordhash, "plaintext"))) + { + ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEFAULT, " tag '%s' at %s contains an plain text password, this is insecure!", + name.c_str(), tag->getTagLocation().c_str()); + } std::string ports = tag->getString("port"); if (!ports.empty()) diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 94fc99db1..d4a02859d 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -307,12 +307,19 @@ class ModuleCgiIRC // The IP address will be received via the WEBIRC command. const std::string fingerprint = tag->getString("fingerprint"); const std::string password = tag->getString("password"); + const std::string passwordhash = tag->getString("hash", "plaintext", 1); // WebIRC blocks require a password. if (fingerprint.empty() && password.empty()) throw ModuleException("When using either the fingerprint or password field is required, at " + tag->getTagLocation()); - webirchosts.push_back(WebIRCHost(mask, fingerprint, password, tag->getString("hash"))); + if (!password.empty() && stdalgo::string::equalsci(passwordhash, "plaintext")) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, " tag at %s contains an plain text password, this is insecure!", + tag->getTagLocation().c_str()); + } + + webirchosts.push_back(WebIRCHost(mask, fingerprint, password, passwordhash)); } else { diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp index faf614e2f..7cdd0bc4f 100644 --- a/src/modules/m_customtitle.cpp +++ b/src/modules/m_customtitle.cpp @@ -136,7 +136,13 @@ class ModuleCustomTitle : public Module, public Whois::LineEventListener if (pass.empty()) throw ModuleException(" is empty at " + tag->getTagLocation()); - std::string hash = tag->getString("hash"); + const std::string hash = tag->getString("hash", "plaintext", 1); + if (stdalgo::string::equalsci(hash, "plaintext")) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, " tag for %s at %s contains an plain text password, this is insecure!", + name.c_str(), tag->getTagLocation().c_str()); + } + std::string host = tag->getString("host", "*@*"); std::string title = tag->getString("title"); std::string vhost = tag->getString("vhost"); diff --git a/src/modules/m_vhost.cpp b/src/modules/m_vhost.cpp index 573b9b31a..43d732ef9 100644 --- a/src/modules/m_vhost.cpp +++ b/src/modules/m_vhost.cpp @@ -103,13 +103,21 @@ class ModuleVHost : public Module std::string mask = tag->getString("host"); if (mask.empty()) throw ModuleException("<vhost:host> is empty! at " + tag->getTagLocation()); + std::string username = tag->getString("user"); if (username.empty()) throw ModuleException("<vhost:user> is empty! at " + tag->getTagLocation()); + std::string pass = tag->getString("pass"); if (pass.empty()) throw ModuleException("<vhost:pass> is empty! at " + tag->getTagLocation()); - std::string hash = tag->getString("hash"); + + const std::string hash = tag->getString("hash", "plaintext", 1); + if (stdalgo::string::equalsci(hash, "plaintext")) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "<vhost> tag for %s at %s contains an plain text password, this is insecure!", + username.c_str(), tag->getTagLocation().c_str()); + } CustomVhost vhost(username, pass, hash, mask); newhosts.insert(std::make_pair(username, vhost)); diff --git a/src/users.cpp b/src/users.cpp index 4edfd574c..0c95ecc0b 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -1155,9 +1155,9 @@ void LocalUser::SetClass(const std::string &explicit_name) } } - if (regdone && !c->config->getString("password").empty()) + if (regdone && !c->password.empty()) { - if (!ServerInstance->PassCompare(this, c->config->getString("password"), password, c->config->getString("hash"))) + if (!ServerInstance->PassCompare(this, c->password, password, c->passwordhash)) { ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEBUG, "Bad password, skipping"); continue; @@ -1290,4 +1290,6 @@ void ConnectClass::Update(const ConnectClass* src) limit = src->limit; resolvehostnames = src->resolvehostnames; ports = src->ports; + password = src->password; + passwordhash = src->passwordhash; } -- cgit v1.3.1-10-gc9f91 From 1a7b4bac42c0c0f4dc9d0081c462d62f193e0da8 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 12 Mar 2020 16:20:46 +1100 Subject: Improve logging for the m_ldap and m_ldapauth modules (#1757). Currently, it is difficult to diagnose LDAP authentication failures, since the logs do not provide sufficient information about what is actually being queried and what actually failed. This increases logging details so that information about the LDAP query is included, for example: Fri Mar 06 2020 08:02:59 ANNOUNCEMENT: Error binding as manager to LDAP server: Invalid credentials (bind dn=cn=adminz,dc=nodomain) Rather than: Fri Mar 06 2020 08:02:59 ANNOUNCEMENT: Error binding as manager to LDAP server: Invalid credentials Same with connection logging: Fri Mar 06 2020 07:59:53 CONNECT: Forbidden connection from jsing!jsing@192.168.200.1 (Invalid credentials (bind dn=uid=jsing,dc=nodomain)) Fri Mar 06 2020 08:01:19 CONNECT: Successful connection from jsing!jsing@192.168.200.1 (dn=uid=jsing,dc=nodomain) --- src/modules/extra/m_ldap.cpp | 38 +++++++++++++++++++++++++++++++++++++- src/modules/m_ldapauth.cpp | 8 +++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/modules/extra/m_ldap.cpp b/src/modules/extra/m_ldap.cpp index 488208a5e..874306e62 100644 --- a/src/modules/extra/m_ldap.cpp +++ b/src/modules/extra/m_ldap.cpp @@ -78,6 +78,7 @@ class LDAPRequest } virtual int run() = 0; + virtual std::string info() = 0; }; class LDAPBind : public LDAPRequest @@ -94,6 +95,7 @@ class LDAPBind : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPSearch : public LDAPRequest @@ -113,6 +115,7 @@ class LDAPSearch : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPAdd : public LDAPRequest @@ -130,6 +133,7 @@ class LDAPAdd : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPDel : public LDAPRequest @@ -145,6 +149,7 @@ class LDAPDel : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPModify : public LDAPRequest @@ -162,6 +167,7 @@ class LDAPModify : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPCompare : public LDAPRequest @@ -179,6 +185,7 @@ class LDAPCompare : public LDAPRequest } int run() CXX11_OVERRIDE; + std::string info() CXX11_OVERRIDE; }; class LDAPService : public LDAPProvider, public SocketThread @@ -396,7 +403,7 @@ class LDAPService : public LDAPProvider, public SocketThread if (res != LDAP_SUCCESS) { - ldap_result->error = ldap_err2string(res); + ldap_result->error = InspIRCd::Format("%s (%s)", ldap_err2string(res), req->info().c_str()); return; } @@ -646,11 +653,21 @@ int LDAPBind::run() return i; } +std::string LDAPBind::info() +{ + return "bind dn=" + who; +} + int LDAPSearch::run() { return ldap_search_ext_s(service->GetConnection(), base.c_str(), searchscope, filter.c_str(), NULL, 0, NULL, NULL, &tv, 0, &message); } +std::string LDAPSearch::info() +{ + return "search base=" + base + " filter=" + filter; +} + int LDAPAdd::run() { LDAPMod** mods = LDAPService::BuildMods(attributes); @@ -659,11 +676,21 @@ int LDAPAdd::run() return i; } +std::string LDAPAdd::info() +{ + return "add dn=" + dn; +} + int LDAPDel::run() { return ldap_delete_ext_s(service->GetConnection(), dn.c_str(), NULL, NULL); } +std::string LDAPDel::info() +{ + return "del dn=" + dn; +} + int LDAPModify::run() { LDAPMod** mods = LDAPService::BuildMods(attributes); @@ -672,6 +699,11 @@ int LDAPModify::run() return i; } +std::string LDAPModify::info() +{ + return "modify base=" + base; +} + int LDAPCompare::run() { berval cred; @@ -683,7 +715,11 @@ int LDAPCompare::run() free(cred.bv_val); return ret; +} +std::string LDAPCompare::info() +{ + return "compare dn=" + dn + " attr=" + attr; } MODULE_INIT(ModuleLDAP) diff --git a/src/modules/m_ldapauth.cpp b/src/modules/m_ldapauth.cpp index b612fe8b2..fb5c69d0d 100644 --- a/src/modules/m_ldapauth.cpp +++ b/src/modules/m_ldapauth.cpp @@ -118,6 +118,9 @@ class BindInterface : public LDAPInterface if (!checkingAttributes && requiredattributes.empty()) { + if (verbose) + ServerInstance->SNO->WriteToSnoMask('c', "Successful connection from %s (dn=%s)", user->GetFullRealHost().c_str(), DN.c_str()); + // We're done, there are no attributes to check SetVHost(user, DN); authed->set(user, 1); @@ -134,6 +137,9 @@ class BindInterface : public LDAPInterface // Only one has to pass passed = true; + if (verbose) + ServerInstance->SNO->WriteToSnoMask('c', "Successful connection from %s (dn=%s)", user->GetFullRealHost().c_str(), DN.c_str()); + SetVHost(user, DN); authed->set(user, 1); } @@ -171,7 +177,7 @@ class BindInterface : public LDAPInterface if (!attrCount) { if (verbose) - ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (unable to validate attributes)", user->GetFullRealHost().c_str()); + ServerInstance->SNO->WriteToSnoMask('c', "Forbidden connection from %s (dn=%s) (unable to validate attributes)", user->GetFullRealHost().c_str(), DN.c_str()); ServerInstance->Users->QuitUser(user, killreason); delete this; } -- cgit v1.3.1-10-gc9f91 From 906e44f687185f6507cba95ec1b565de4936eb03 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 11 Mar 2020 19:51:26 +0000 Subject: Add a CapReference class for the message-tags capability. --- include/modules/ctctags.h | 11 +++++++++++ src/modules/m_botmode.cpp | 6 +++--- src/modules/m_ircv3_msgid.cpp | 5 ++--- src/modules/m_spanningtree/tags.cpp | 2 +- src/modules/m_spanningtree/tags.h | 4 ++-- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/include/modules/ctctags.h b/include/modules/ctctags.h index ad45d12b1..7946c1243 100644 --- a/include/modules/ctctags.h +++ b/include/modules/ctctags.h @@ -20,14 +20,25 @@ #pragma once #include "event.h" +#include "modules/cap.h" namespace CTCTags { + class CapReference; class EventListener; class TagMessage; class TagMessageDetails; } +class CTCTags::CapReference : public Cap::Reference +{ + public: + CapReference(Module* mod) + : Cap::Reference(mod, "message-tags") + { + } +}; + class CTCTags::TagMessage : public ClientProtocol::Message { private: diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp index 91623a1fb..355ea44d4 100644 --- a/src/modules/m_botmode.cpp +++ b/src/modules/m_botmode.cpp @@ -24,7 +24,7 @@ #include "inspircd.h" -#include "modules/cap.h" +#include "modules/ctctags.h" #include "modules/whois.h" enum @@ -37,13 +37,13 @@ class BotTag : public ClientProtocol::MessageTagProvider { private: SimpleUserModeHandler& botmode; - Cap::Reference ctctagcap; + CTCTags::CapReference ctctagcap; public: BotTag(Module* mod, SimpleUserModeHandler& bm) : ClientProtocol::MessageTagProvider(mod) , botmode(bm) - , ctctagcap(mod, "message-tags") + , ctctagcap(mod) { } diff --git a/src/modules/m_ircv3_msgid.cpp b/src/modules/m_ircv3_msgid.cpp index 8b56ba6c7..c2bf3bd33 100644 --- a/src/modules/m_ircv3_msgid.cpp +++ b/src/modules/m_ircv3_msgid.cpp @@ -18,18 +18,17 @@ #include "inspircd.h" -#include "modules/cap.h" #include "modules/ctctags.h" class MsgIdTag : public ClientProtocol::MessageTagProvider { private: - Cap::Reference ctctagcap; + CTCTags::CapReference ctctagcap; public: MsgIdTag(Module* mod) : ClientProtocol::MessageTagProvider(mod) - , ctctagcap(mod, "message-tags") + , ctctagcap(mod) { } diff --git a/src/modules/m_spanningtree/tags.cpp b/src/modules/m_spanningtree/tags.cpp index feaa34bca..7ae26d45b 100644 --- a/src/modules/m_spanningtree/tags.cpp +++ b/src/modules/m_spanningtree/tags.cpp @@ -21,7 +21,7 @@ ServiceTag::ServiceTag(Module* mod) : ClientProtocol::MessageTagProvider(mod) - , ctctagcap(mod, "message-tags") + , ctctagcap(mod) { } diff --git a/src/modules/m_spanningtree/tags.h b/src/modules/m_spanningtree/tags.h index d8d863a45..a52ee6ef8 100644 --- a/src/modules/m_spanningtree/tags.h +++ b/src/modules/m_spanningtree/tags.h @@ -19,12 +19,12 @@ #pragma once -#include "modules/cap.h" +#include "modules/ctctags.h" class ServiceTag : public ClientProtocol::MessageTagProvider { private: - Cap::Reference ctctagcap; + CTCTags::CapReference ctctagcap; public: ServiceTag(Module* mod); -- cgit v1.3.1-10-gc9f91 From 1efc234a54bd66714f9743ca7d1f3d5c0be3628e Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 12 Mar 2020 17:27:11 +0000 Subject: Implement support for the SERVLIST command. --- include/moduledefs.h | 2 +- include/usermanager.h | 11 +++--- src/coremods/core_info/cmd_servlist.cpp | 59 +++++++++++++++++++++++++++++++++ src/coremods/core_info/core_info.cpp | 4 ++- src/coremods/core_info/core_info.h | 10 ++++++ src/usermanager.cpp | 1 - src/users.cpp | 6 ++-- 7 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 src/coremods/core_info/cmd_servlist.cpp diff --git a/include/moduledefs.h b/include/moduledefs.h index 9f54e3eeb..a706a8883 100644 --- a/include/moduledefs.h +++ b/include/moduledefs.h @@ -22,7 +22,7 @@ class Module; /** The version of the InspIRCd ABI which is presently in use. */ -#define MODULE_ABI 3011UL +#define MODULE_ABI 3012UL /** Stringifies the value of a symbol. */ #define MODULE_STRINGIFY_SYM1(DEF) MODULE_STRINGIFY_SYM2(DEF) diff --git a/include/usermanager.h b/include/usermanager.h index ad09d968c..2a18393ab 100644 --- a/include/usermanager.h +++ b/include/usermanager.h @@ -46,6 +46,9 @@ class CoreExport UserManager : public fakederef<UserManager> */ typedef std::vector<User*> OperList; + /** A list containing users who are on a U-lined servers. */ + typedef std::vector<User*> ULineList; + /** A list holding local users */ typedef insp::intrusive_list<LocalUser> LocalList; @@ -89,14 +92,14 @@ class CoreExport UserManager : public fakederef<UserManager> */ OperList all_opers; + /** A list of users on U-lined servers. */ + ULineList all_ulines; + /** Number of unregistered users online right now. * (Unregistered means before USER/NICK/dns) */ unsigned int unregistered_count; - /** The number of users on U-lined servers. */ - unsigned int uline_count; - /** Perform background user events for all local users such as PING checks, registration timeouts, * penalty management and recvq processing for users who have data in their recvq due to throttling. */ @@ -175,7 +178,7 @@ class CoreExport UserManager : public fakederef<UserManager> /** Return a count of users on a u-lined servers. * @return The number of users on u-lined servers. */ - unsigned int ULineCount() const { return this->uline_count; } + unsigned int ULineCount() const { return this->all_ulines.size(); } /** Return a count of local registered users * @return The number of registered local users diff --git a/src/coremods/core_info/cmd_servlist.cpp b/src/coremods/core_info/cmd_servlist.cpp new file mode 100644 index 000000000..f400124d2 --- /dev/null +++ b/src/coremods/core_info/cmd_servlist.cpp @@ -0,0 +1,59 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2020 Sadie Powell <sadie@witchery.services> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "core_info.h" + +enum +{ + // From RFC 2812. + RPL_SERVLIST = 234, + RPL_SERVLISTEND = 235 +}; + +CommandServList::CommandServList(Module* parent) + : SplitCommand(parent, "SERVLIST") + , invisiblemode(parent, "invisible") +{ + allow_empty_last_param = false; + syntax = "[<mask>]"; +} + +CmdResult CommandServList::HandleLocal(LocalUser* user, const Params& parameters) +{ + const std::string& mask = parameters.empty() ? "*" : parameters[0]; + for (UserManager::ULineList::const_iterator iter = ServerInstance->Users.all_ulines.begin(); iter != ServerInstance->Users.all_ulines.end(); ++iter) + { + User* uline = *iter; + if (uline->IsModeSet(invisiblemode) || !InspIRCd::Match(uline->nick, mask)) + continue; + + Numeric::Numeric numeric(RPL_SERVLIST); + numeric + .push(uline->nick) + .push(uline->server->GetName()) + .push(mask) + .push(0) + .push(0) + .push(uline->GetRealName()); + user->WriteNumeric(numeric); + } + user->WriteNumeric(RPL_SERVLISTEND, mask, 0, "End of service listing"); + return CMD_SUCCESS; +} diff --git a/src/coremods/core_info/core_info.cpp b/src/coremods/core_info/core_info.cpp index 507e43250..b172372e5 100644 --- a/src/coremods/core_info/core_info.cpp +++ b/src/coremods/core_info/core_info.cpp @@ -46,6 +46,7 @@ class CoreModInfo : public Module CommandInfo cmdinfo; CommandModules cmdmodules; CommandMotd cmdmotd; + CommandServList cmdservlist; CommandTime cmdtime; CommandVersion cmdversion; Numeric::Numeric numeric004; @@ -91,6 +92,7 @@ class CoreModInfo : public Module , cmdinfo(this) , cmdmodules(this) , cmdmotd(this) + , cmdservlist(this) , cmdtime(this) , cmdversion(this) , numeric004(RPL_MYINFO) @@ -176,7 +178,7 @@ class CoreModInfo : public Module Version GetVersion() CXX11_OVERRIDE { - return Version("Provides the ADMIN, COMMANDS, INFO, MODULES, MOTD, TIME, and VERSION commands", VF_VENDOR|VF_CORE); + return Version("Provides the ADMIN, COMMANDS, INFO, MODULES, MOTD, TIME, SERVLIST, and VERSION commands", VF_VENDOR|VF_CORE); } }; diff --git a/src/coremods/core_info/core_info.h b/src/coremods/core_info/core_info.h index 08aab4cd1..ecd4f78e7 100644 --- a/src/coremods/core_info/core_info.h +++ b/src/coremods/core_info/core_info.h @@ -137,6 +137,16 @@ class CommandMotd : public ServerTargetCommand CmdResult Handle(User* user, const Params& parameters) CXX11_OVERRIDE; }; +class CommandServList : public SplitCommand +{ + private: + UserModeReference invisiblemode; + + public: + CommandServList(Module* parent); + CmdResult HandleLocal(LocalUser* user, const Params& parameters) CXX11_OVERRIDE; +}; + /** Handle /TIME. */ class CommandTime : public ServerTargetCommand diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 9c8bde1e2..812f43113 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -119,7 +119,6 @@ namespace UserManager::UserManager() : already_sent_id(0) , unregistered_count(0) - , uline_count(0) { } diff --git a/src/users.cpp b/src/users.cpp index 0c95ecc0b..2571d15f2 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -91,7 +91,7 @@ User::User(const std::string& uid, Server* srv, UserType type) ServerInstance->Logs->Log("USERS", LOG_DEBUG, "New UUID for user: %s", uuid.c_str()); if (srv->IsULine()) - ServerInstance->Users->uline_count++; + ServerInstance->Users.all_ulines.push_back(this); // Do not insert FakeUsers into the uuidlist so FindUUID() won't return them which is the desired behavior if (type != USERTYPE_SERVER) @@ -354,8 +354,8 @@ CullResult User::cull() if (client_sa.family() != AF_UNSPEC) ServerInstance->Users->RemoveCloneCounts(this); - if (server->IsULine() && ServerInstance->Users->uline_count) - ServerInstance->Users->uline_count--; + if (server->IsULine()) + stdalgo::erase(ServerInstance->Users->all_ulines, this); return Extensible::cull(); } -- cgit v1.3.1-10-gc9f91 From 176acbfdb0fde4d6f3b808a6af80e651220b96b7 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Thu, 12 Mar 2020 18:24:50 +0000 Subject: Move CHANMODES to core_mode and add USERMODES. --- src/coremods/core_mode.cpp | 6 ++++++ src/server.cpp | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coremods/core_mode.cpp b/src/coremods/core_mode.cpp index 99dcf8638..f40d02d2e 100644 --- a/src/coremods/core_mode.cpp +++ b/src/coremods/core_mode.cpp @@ -285,6 +285,12 @@ class CoreModMode : public Module { } + void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE + { + tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL); + tokens["USERMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_USER); + } + Version GetVersion() CXX11_OVERRIDE { return Version("Provides the MODE command", VF_VENDOR|VF_CORE); diff --git a/src/server.cpp b/src/server.cpp index 79f2d8f4d..3a888dc4e 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -194,7 +194,6 @@ void ISupportManager::Build() tokens["AWAYLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxAway); tokens["CASEMAPPING"] = ServerInstance->Config->CaseMapping; tokens["CHANLIMIT"] = InspIRCd::Format("#:%u", ServerInstance->Config->MaxChans); - tokens["CHANMODES"] = ServerInstance->Modes->GiveModeList(MODETYPE_CHANNEL); tokens["CHANNELLEN"] = ConvToStr(ServerInstance->Config->Limits.ChanMax); tokens["CHANTYPES"] = "#"; tokens["HOSTLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxHost); -- cgit v1.3.1-10-gc9f91 From e91a017aca2d314f4d9f4cd20ac17bb6e3b97eb4 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Fri, 13 Mar 2020 07:58:34 +0000 Subject: Force people to use an issue template. --- .github/ISSUE_TEMPLATE/config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3ba13e0ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false -- cgit v1.3.1-10-gc9f91 From 92d83e91038eb54a8200815d5d948c2b61dacce4 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 18 Mar 2020 10:54:37 +0000 Subject: Allow commands to override ERR_{NEEDSMOREPARAMS,NOTREGISTERED}. --- include/ctables.h | 12 ++++++++++++ src/command_parse.cpp | 6 ++---- src/commands.cpp | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/ctables.h b/include/ctables.h index a3fcdfbd4..22c0ef67e 100644 --- a/include/ctables.h +++ b/include/ctables.h @@ -236,6 +236,18 @@ class CoreExport Command : public CommandBase /** Registers this command with the command parser. */ void RegisterService() CXX11_OVERRIDE; + + /** Tells the user they did not specify enough parameters. + * @param user The user who issued the command. + * @param parameters The parameters for the command. + */ + virtual void TellNotEnoughParameters(LocalUser* user, const Params& parameters); + + /** Tells the user they need to be registered to execute this command. + * @param user The user who issued the command. + * @param parameters The parameters for the command. + */ + virtual void TellNotRegistered(LocalUser* user, const Params& parameters); }; class CoreExport SplitCommand : public Command diff --git a/src/command_parse.cpp b/src/command_parse.cpp index c4e55c3ca..717431087 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -283,9 +283,7 @@ void CommandParser::ProcessCommand(LocalUser* user, std::string& command, Comman if (command_p.size() < handler->min_params) { user->CommandFloodPenalty += failpenalty; - user->WriteNumeric(ERR_NEEDMOREPARAMS, command, "Not enough parameters."); - if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length())) - user->WriteNumeric(RPL_SYNTAX, handler->name, handler->syntax); + handler->TellNotEnoughParameters(user, command_p); FOREACH_MOD(OnCommandBlocked, (command, command_p, user)); return; } @@ -293,7 +291,7 @@ void CommandParser::ProcessCommand(LocalUser* user, std::string& command, Comman if ((user->registered != REG_ALL) && (!handler->works_before_reg)) { user->CommandFloodPenalty += failpenalty; - user->WriteNumeric(ERR_NOTREGISTERED, command, "You have not registered"); + handler->TellNotRegistered(user, command_p); FOREACH_MOD(OnCommandBlocked, (command, command_p, user)); } else diff --git a/src/commands.cpp b/src/commands.cpp index 8343cfaac..d1746bc5f 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -66,6 +66,17 @@ void Command::RegisterService() throw ModuleException("Command already exists: " + name); } +void Command::TellNotEnoughParameters(LocalUser* user, const Params& parameters) +{ + user->WriteNumeric(ERR_NEEDMOREPARAMS, name, "Not enough parameters."); + if (ServerInstance->Config->SyntaxHints && user->registered == REG_ALL && syntax.length()) + user->WriteNumeric(RPL_SYNTAX, name, syntax); +} + +void Command::TellNotRegistered(LocalUser* user, const Params& parameters) +{ + user->WriteNumeric(ERR_NOTREGISTERED, name, "You have not registered."); +} SplitCommand::SplitCommand(Module* me, const std::string& cmd, unsigned int minpara, unsigned int maxpara) : Command(me, cmd, minpara, maxpara) -- cgit v1.3.1-10-gc9f91