aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Sadie Powell2020-03-18 13:51:23 +0000
committerGravatar Sadie Powell2020-03-18 13:51:23 +0000
commitb9acde9aaf0ddae8b821b21821724adcdbea9359 (patch)
tree7c76b8988dd9e31596ae2b114b15a762561e063d
parentRemove support for 0/1 in getBool. (diff)
parentAllow commands to override ERR_{NEEDSMOREPARAMS,NOTREGISTERED}. (diff)
Merge branch 'insp3' into master.
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml1
-rwxr-xr-xconfigure2
-rw-r--r--docs/conf/inspircd.conf.example2
-rw-r--r--docs/conf/modules.conf.example29
-rw-r--r--include/ctables.h113
-rw-r--r--include/message.h3
-rw-r--r--include/modules/ctctags.h14
-rw-r--r--include/server.h2
-rw-r--r--include/usermanager.h11
-rw-r--r--include/users.h6
-rw-r--r--src/command_parse.cpp46
-rw-r--r--src/commands.cpp53
-rw-r--r--src/configparser.cpp19
-rw-r--r--src/configreader.cpp8
-rw-r--r--src/coremods/core_info/cmd_servlist.cpp59
-rw-r--r--src/coremods/core_info/core_info.cpp4
-rw-r--r--src/coremods/core_info/core_info.h10
-rw-r--r--src/coremods/core_info/isupport.cpp1
-rw-r--r--src/coremods/core_loadmodule.cpp8
-rw-r--r--src/coremods/core_message.cpp2
-rw-r--r--src/coremods/core_mode.cpp14
-rw-r--r--src/inspircd.cpp27
-rw-r--r--src/listensocket.cpp3
-rw-r--r--src/modules/extra/m_ldap.cpp38
-rw-r--r--src/modules/m_botmode.cpp6
-rw-r--r--src/modules/m_cap.cpp89
-rw-r--r--src/modules/m_cgiirc.cpp9
-rw-r--r--src/modules/m_check.cpp3
-rw-r--r--src/modules/m_customtitle.cpp8
-rw-r--r--src/modules/m_cycle.cpp3
-rw-r--r--src/modules/m_globalload.cpp3
-rw-r--r--src/modules/m_globops.cpp3
-rw-r--r--src/modules/m_httpd.cpp30
-rw-r--r--src/modules/m_ident.cpp3
-rw-r--r--src/modules/m_ircv3_ctctags.cpp2
-rw-r--r--src/modules/m_ircv3_msgid.cpp5
-rw-r--r--src/modules/m_ircv3_sts.cpp2
-rw-r--r--src/modules/m_ldapauth.cpp8
-rw-r--r--src/modules/m_ojoin.cpp3
-rw-r--r--src/modules/m_opermotd.cpp3
-rw-r--r--src/modules/m_sakick.cpp3
-rw-r--r--src/modules/m_samode.cpp3
-rw-r--r--src/modules/m_sasl.cpp15
-rw-r--r--src/modules/m_satopic.cpp3
-rw-r--r--src/modules/m_sethost.cpp3
-rw-r--r--src/modules/m_setident.cpp3
-rw-r--r--src/modules/m_setidle.cpp3
-rw-r--r--src/modules/m_spanningtree/tags.cpp2
-rw-r--r--src/modules/m_spanningtree/tags.h4
-rw-r--r--src/modules/m_sslinfo.cpp5
-rw-r--r--src/modules/m_swhois.cpp3
-rw-r--r--src/modules/m_vhost.cpp10
-rw-r--r--src/usermanager.cpp1
-rw-r--r--src/users.cpp12
-rwxr-xr-xtools/test-build2
55 files changed, 516 insertions, 211 deletions
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
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/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example
index 61524deaa..eef4dd685 100644
--- a/docs/conf/inspircd.conf.example
+++ b/docs/conf/inspircd.conf.example
@@ -709,7 +709,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 868b48d64..468fc675d 100644
--- a/docs/conf/modules.conf.example
+++ b/docs/conf/modules.conf.example
@@ -1184,14 +1184,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.
#
-# <sts host="*.example.com" duration="60d" port="6697" preload="yes">
+# <sts host="*.example.com" duration="5m" port="6697" preload="yes">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Join flood module: Adds support for join flood protection +j X:Y.
@@ -1550,7 +1551,13 @@
# requirekey - If enabled, overriding on join requires a channel #
# key of "override" to be specified. #
# #
+<<<<<<< HEAD
#<override noisy="yes" requirekey="no">
+=======
+# enableumode - If enabled, user mode +O is required for override. #
+# #
+#<override noisy="yes" requirekey="no" enableumode="yes">
+>>>>>>> insp3
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Oper levels module: Gives each oper a level and prevents actions
@@ -1646,7 +1653,7 @@
# 'saveperiod' determines how often to check if the database needs to be
# saved to disk. Defaults to every five seconds.
#<permchanneldb filename="permchannels.conf"
-# listmodes="true"
+# listmodes="yes"
# saveperiod="5s">
#<include file="permchannels.conf">
#
@@ -1751,7 +1758,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.
-#<remove supportnokicks="true" protectedrank="50000">
+#<remove supportnokicks="yes" protectedrank="50000">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Repeat module: Allows to block, kick or ban upon similar messages
@@ -1894,12 +1901,14 @@
# Layer via AUTHENTICATE. Note: You also need to have cap loaded
# for SASL to work.
#<module name="sasl">
-# 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.
-#<sasl target="services.mynetwork.com">
+
+# You must define <sasl:target> 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 <sasl:requiressl> to require users to use SSL in
+# order to be able to use SASL.
+#<sasl target="services.mynetwork.com"
+# requiressl="yes">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Secure list module: Prevent /LIST in the first minute of connection,
diff --git a/include/ctables.h b/include/ctables.h
index 91eb5eb00..0d115ae9a 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 = 0;
-
/** 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 = 0;
-
- /** True if the command can be issued before registering
- */
- bool works_before_reg = false;
-
/** 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 = true;
- /** 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<TranslateType> translation;
- /** How many seconds worth of penalty does this command have?
- */
- unsigned int Penalty = 1;
-
/** Create a new command.
* @param me The module which created this command.
* @param cmd Command name. This must be UPPER CASE.
@@ -211,50 +190,102 @@ 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:
- /** 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.
+ 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() override;
+
+ /** The user modes required to be able to execute this command. */
+ unsigned char flags_needed = 0;
+
+ /** Whether the command will not be forwarded by the linking module even if it comes via ENCAP. */
bool force_manual_route = false;
- Command(Module* me, const std::string& cmd, unsigned int minpara = 0, unsigned int maxpara = 0);
+ /** The number of seconds worth of penalty that executing this command gives. */
+ unsigned int Penalty = 1;
+
+ /** The number of times this command has been executed. */
+ unsigned long use_count = 0;
+
+ /** 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 = false;
/** 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() override;
- /** Destructor
- * Removes this command from the command parser
+ /** Tells the user they did not specify enough parameters.
+ * @param user The user who issued the command.
+ * @param parameters The parameters for the command.
*/
- ~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
{
+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) 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/include/message.h b/include/message.h
index 5631aa25f..e168b161a 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 = false;
+ /** Whether to update the source user's idle time. */
+ bool update_idle = true;
+
/** The users who are exempted from receiving this message. */
CUList exemptions;
diff --git a/include/modules/ctctags.h b/include/modules/ctctags.h
index f51e5345f..12422dd8a 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:
@@ -85,6 +96,9 @@ class CTCTags::TagMessageDetails
/* Whether to send the original tags back to clients with echo-message support. */
bool echo_original = false;
+ /** Whether to update the source user's idle time. */
+ bool update_idle = true;
+
/** The users who are exempted from receiving this message. */
CUList exemptions;
diff --git a/include/server.h b/include/server.h
index 23c89d2c4..6caed03b6 100644
--- a/include/server.h
+++ b/include/server.h
@@ -40,7 +40,7 @@ class CoreExport Server : public classbase
*/
bool uline = false;
- /** 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 = false;
diff --git a/include/usermanager.h b/include/usermanager.h
index 6a5c6bb4e..413494804 100644
--- a/include/usermanager.h
+++ b/include/usermanager.h
@@ -45,6 +45,9 @@ class CoreExport 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;
@@ -88,14 +91,14 @@ class CoreExport 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.
*/
@@ -164,7 +167,7 @@ class CoreExport 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/include/users.h b/include/users.h
index f631d4da3..78c171d25 100644
--- a/include/users.h
+++ b/include/users.h
@@ -149,6 +149,12 @@ struct CoreExport ConnectClass : public refcountbase
*/
insp::flat_set<int> 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/command_parse.cpp b/src/command_parse.cpp
index d511723dc..64b480435 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);
@@ -283,17 +283,15 @@ 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;
}
- 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");
+ handler->TellNotRegistered(user, command_p);
FOREACH_MOD(OnCommandBlocked, (command, command_p, user));
}
else
@@ -325,42 +323,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)
-{
-}
-
-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)
-{
-}
-
-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 12013942a..6ca6620d5 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -24,6 +24,59 @@
#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)
+{
+}
+
+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)
+{
+}
+
+Command::~Command()
+{
+ ServerInstance->Parser.RemoveCommand(this);
+}
+
+void Command::RegisterService()
+{
+ if (!ServerInstance->Parser.AddCommand(this))
+ 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)
+{
+}
+
CmdResult SplitCommand::Handle(User* user, const Params& parameters)
{
switch (user->usertype)
diff --git a/src/configparser.cpp b/src/configparser.cpp
index 2fcd59d4a..7cd4b499b 100644
--- a/src/configparser.cpp
+++ b/src/configparser.cpp
@@ -153,12 +153,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();
@@ -200,7 +208,7 @@ struct Parser
while (1)
{
ch = next();
- if (isalnum(ch) || (varname.empty() && ch == '#'))
+ if (wordchar(ch) || (varname.empty() && ch == '#'))
varname.push_back(ch);
else if (ch == ';')
break;
@@ -228,6 +236,13 @@ struct Parser
throw CoreException("Invalid numeric character reference '&" + varname + ";'");
value.push_back(static_cast<char>(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<std::string, std::string>::iterator var = stack.vars.find(varname);
diff --git a/src/configreader.cpp b/src/configreader.cpp
index 7d4e30672..b9bca0443 100644
--- a/src/configreader.cpp
+++ b/src/configreader.cpp
@@ -303,6 +303,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, "<connect> 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/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 7a75052e1..8e2b026a5 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;
@@ -93,6 +94,7 @@ class CoreModInfo : public Module
, cmdinfo(this)
, cmdmodules(this)
, cmdmotd(this)
+ , cmdservlist(this)
, cmdtime(this)
, cmdversion(this, isupport)
, numeric004(RPL_MYINFO)
@@ -189,7 +191,7 @@ class CoreModInfo : public Module
Version GetVersion() 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 67a694945..fd21d2f57 100644
--- a/src/coremods/core_info/core_info.h
+++ b/src/coremods/core_info/core_info.h
@@ -174,6 +174,16 @@ class CommandMotd : public ServerTargetCommand
CmdResult Handle(User* user, const Params& parameters) override;
};
+class CommandServList : public SplitCommand
+{
+ private:
+ UserModeReference invisiblemode;
+
+ public:
+ CommandServList(Module* parent);
+ CmdResult HandleLocal(LocalUser* user, const Params& parameters) override;
+};
+
/** Handle /TIME.
*/
class CommandTime : public ServerTargetCommand
diff --git a/src/coremods/core_info/isupport.cpp b/src/coremods/core_info/isupport.cpp
index 6e53c446b..468612674 100644
--- a/src/coremods/core_info/isupport.cpp
+++ b/src/coremods/core_info/isupport.cpp
@@ -56,7 +56,6 @@ void ISupportManager::Build()
tokens["AWAYLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxAway);
tokens["CASEMAPPING"] = ServerInstance->Config->CaseMapping;
- tokens["CHANMODES"] = ServerInstance->Modes.GiveModeList(MODETYPE_CHANNEL);
tokens["CHANNELLEN"] = ConvToStr(ServerInstance->Config->Limits.ChanMax);
tokens["CHANTYPES"] = "#";
tokens["HOSTLEN"] = ConvToStr(ServerInstance->Config->Limits.MaxHost);
diff --git a/src/coremods/core_loadmodule.cpp b/src/coremods/core_loadmodule.cpp
index fc2143563..8928aa182 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 = "<modulename>"; }
+ CommandLoadmodule(Module* parent)
+ : Command(parent,"LOADMODULE", 1, 1)
+ {
+ flags_needed = 'o';
+ syntax = "<modulename>";
+ }
+
/** Handle command.
* @param parameters The parameters to the command
* @param user The user issuing the command
diff --git a/src/coremods/core_message.cpp b/src/coremods/core_message.cpp
index 82a56c134..aa018ae6f 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/coremods/core_mode.cpp b/src/coremods/core_mode.cpp
index 4489b87fc..f431d954c 100644
--- a/src/coremods/core_mode.cpp
+++ b/src/coremods/core_mode.cpp
@@ -22,6 +22,7 @@
#include "inspircd.h"
+#include "modules/isupport.h"
class CommandMode : public Command
{
@@ -273,17 +274,26 @@ void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* tar
}
}
-class CoreModMode : public Module
+class CoreModMode
+ : public Module
+ , public ISupport::EventListener
{
private:
CommandMode cmdmode;
public:
CoreModMode()
- : cmdmode(this)
+ : ISupport::EventListener(this)
+ , cmdmode(this)
{
}
+ void OnBuildISupport(ISupport::TokenMap& tokens) override
+ {
+ tokens["CHANMODES"] = ServerInstance->Modes.GiveModeList(MODETYPE_CHANNEL);
+ tokens["USERMODES"] = ServerInstance->Modes.GiveModeList(MODETYPE_USER);
+ }
+
Version GetVersion() override
{
return Version("Provides the MODE command", VF_VENDOR|VF_CORE);
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index e3ea33d6a..38f23cc2f 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 <security:runas{user,group}>.
void DropRoot()
{
@@ -656,17 +671,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;
diff --git a/src/listensocket.cpp b/src/listensocket.cpp
index 2e7b42720..482bd9b12 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/extra/m_ldap.cpp b/src/modules/extra/m_ldap.cpp
index 46b76ab5f..d536dc0ed 100644
--- a/src/modules/extra/m_ldap.cpp
+++ b/src/modules/extra/m_ldap.cpp
@@ -76,6 +76,7 @@ class LDAPRequest
}
virtual int run() = 0;
+ virtual std::string info() = 0;
};
class LDAPBind : public LDAPRequest
@@ -92,6 +93,7 @@ class LDAPBind : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPSearch : public LDAPRequest
@@ -111,6 +113,7 @@ class LDAPSearch : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPAdd : public LDAPRequest
@@ -128,6 +131,7 @@ class LDAPAdd : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPDel : public LDAPRequest
@@ -143,6 +147,7 @@ class LDAPDel : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPModify : public LDAPRequest
@@ -160,6 +165,7 @@ class LDAPModify : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPCompare : public LDAPRequest
@@ -177,6 +183,7 @@ class LDAPCompare : public LDAPRequest
}
int run() override;
+ std::string info() override;
};
class LDAPService : public LDAPProvider, public SocketThread
@@ -394,7 +401,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;
}
@@ -644,11 +651,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);
@@ -657,11 +674,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);
@@ -670,6 +697,11 @@ int LDAPModify::run()
return i;
}
+std::string LDAPModify::info()
+{
+ return "modify base=" + base;
+}
+
int LDAPCompare::run()
{
berval cred;
@@ -681,7 +713,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_botmode.cpp b/src/modules/m_botmode.cpp
index 73f4a1f50..6fc2ddde3 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_cap.cpp b/src/modules/m_cap.cpp
index ac8181df0..7f3cd7658 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<Capability::Bit>(1) << i);
if (!(used & bit))
return bit;
}
@@ -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<std::string>& 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<std::string>& 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<std::string> 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<std::string> 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<std::string>::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<std::string> 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<std::string> result;
manager.HandleClear(user, result);
- DisplayResult(user, "ACK", result);
+ DisplayResult(user, "ACK", result, false);
}
else
{
diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp
index 94b7dab4d..241eb118b 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 <cgihost type=\"webirc\"> 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, "<cgihost> 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_check.cpp b/src/modules/m_check.cpp
index b4127929e..a818f3abf 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 = "<nick>|<ipmask>|<hostmask>|<channel> [<servername>]";
+ flags_needed = 'o';
+ syntax = "<nick>|<ipmask>|<hostmask>|<channel> [<servername>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp
index fe4fe9d1d..1f2748edb 100644
--- a/src/modules/m_customtitle.cpp
+++ b/src/modules/m_customtitle.cpp
@@ -137,7 +137,13 @@ class ModuleCustomTitle : public Module, public Whois::LineEventListener
if (pass.empty())
throw ModuleException("<title:password> 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, "<title> 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_cycle.cpp b/src/modules/m_cycle.cpp
index 579183b15..0c6d57d48 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 = "<channel> [:<reason>]";
+ Penalty = 3;
+ syntax = "<channel> [:<reason>]";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp
index 718b1d637..0bb1c8973 100644
--- a/src/modules/m_globalload.cpp
+++ b/src/modules/m_globalload.cpp
@@ -123,7 +123,8 @@ class CommandGreloadmodule : public Command
public:
CommandGreloadmodule(Module* Creator) : Command(Creator, "GRELOADMODULE", 1)
{
- flags_needed = 'o'; syntax = "<modulename> [<servermask>]";
+ flags_needed = 'o';
+ syntax = "<modulename> [<servermask>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp
index 5e4715b24..85b2848cc 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 = ":<message>";
+ flags_needed = 'o';
+ syntax = ":<message>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp
index 5bf7d8bdc..06bdb1ae7 100644
--- a/src/modules/m_httpd.cpp
+++ b/src/modules/m_httpd.cpp
@@ -81,7 +81,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
{
if (!messagecomplete)
{
- AddToCull();
+ Close();
return false;
}
@@ -212,7 +212,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
// IOHook may have errored
if (!getError().empty())
{
- AddToCull();
+ Close();
return;
}
}
@@ -227,9 +227,19 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
sockets.erase(this);
}
+ void Close() override
+ {
+ if (waitingcull || !HasFd())
+ return;
+
+ waitingcull = true;
+ BufferedSocket::Close();
+ ServerInstance->GlobalCulls.AddItem(this);
+ }
+
void OnError(BufferedSocketError) override
{
- AddToCull();
+ Close();
}
void SendHTTPError(unsigned int response)
@@ -298,7 +308,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)
@@ -306,16 +316,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);
@@ -422,7 +422,7 @@ class ModuleHttpServer : public Module
for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i)
{
HttpServerSocket* sock = *i;
- sock->AddToCull();
+ sock->Close();
}
return Module::cull();
}
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index 8b54183ed..3a48ac97a 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;
diff --git a/src/modules/m_ircv3_ctctags.cpp b/src/modules/m_ircv3_ctctags.cpp
index 66f2869c8..0babae709 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.
diff --git a/src/modules/m_ircv3_msgid.cpp b/src/modules/m_ircv3_msgid.cpp
index f30000912..0c51adee2 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_ircv3_sts.cpp b/src/modules/m_ircv3_sts.cpp
index dbf99153e..0abc4b3be 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("<sts:port> 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);
diff --git a/src/modules/m_ldapauth.cpp b/src/modules/m_ldapauth.cpp
index 22b0e1fbe..26a50c145 100644
--- a/src/modules/m_ldapauth.cpp
+++ b/src/modules/m_ldapauth.cpp
@@ -120,6 +120,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);
@@ -136,6 +139,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);
}
@@ -173,7 +179,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;
}
diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp
index da499ae36..299499886 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 = "<channel>";
+ flags_needed = 'o';
+ syntax = "<channel>";
active = false;
}
diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp
index eac1447dc..3f4c99b09 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 = "[<servername>]";
+ flags_needed = 'o';
+ syntax = "[<servername>]";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp
index ad5857291..262470fc8 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 = "<channel> <nick> [:<reason>]";
+ flags_needed = 'o';
+ syntax = "<channel> <nick> [:<reason>]";
translation = { TR_TEXT, TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp
index ba3b34aed..20c2a9671 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 = "<target> (+|-)<modes> [<mode-parameters>]";
+ flags_needed = 'o';
+ syntax = "<target> (+|-)<modes> [<mode-parameters>]";
active = false;
}
diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp
index 6ef2ea12e..a5b8f2cc9 100644
--- a/src/modules/m_sasl.cpp
+++ b/src/modules/m_sasl.cpp
@@ -106,11 +106,16 @@ class ServerTracker
class SASLCap : public Cap::Capability
{
+ private:
std::string mechlist;
const ServerTracker& servertracker;
+ UserCertificateAPI sslapi;
bool OnRequest(LocalUser* user, bool adding) 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();
@@ -118,6 +123,9 @@ class SASLCap : public Cap::Capability
bool OnList(LocalUser* user) 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();
@@ -129,9 +137,11 @@ class SASLCap : public Cap::Capability
}
public:
+ bool requiressl;
SASLCap(Module* mod, const ServerTracker& tracker)
: Cap::Capability(mod, "sasl")
, servertracker(tracker)
+ , sslapi(mod)
{
}
@@ -421,10 +431,13 @@ class ModuleSASL : public Module
void ReadConfig(ConfigStatus& status) 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("<sasl:target> must be set to the name of your services server!");
+ cap.requiressl = tag->getBool("requiressl");
sasl_target = target;
servertracker.Reset();
}
diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp
index 01431b4c7..39b2e8431 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 = "<channel> :<topic>";
+ flags_needed = 'o';
+ syntax = "<channel> :<topic>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp
index 98107d6ee..0ab6c3444 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 = "<host>";
+ flags_needed = 'o';
+ syntax = "<host>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp
index e1ea32bdd..3f8ecc3da 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 = "<ident>";
+ flags_needed = 'o';
+ syntax = "<ident>";
}
CmdResult Handle(User* user, const Params& parameters) override
diff --git a/src/modules/m_setidle.cpp b/src/modules/m_setidle.cpp
index 97c940b76..d8f5f57f3 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 = "<duration>";
+ flags_needed = 'o';
+ syntax = "<duration>";
}
CmdResult HandleLocal(LocalUser* user, const Params& parameters) override
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 ac2f7e876..6f2f68762 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);
diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp
index edfc00823..3b6ed3e5c 100644
--- a/src/modules/m_sslinfo.cpp
+++ b/src/modules/m_sslinfo.cpp
@@ -215,7 +215,7 @@ class ModuleSSLInfo
Version GetVersion() override
{
- return Version("SSL Certificate Utilities", VF_VENDOR);
+ return Version("Provides user SSL information and certificate utilities", VF_VENDOR);
}
void OnWhois(Whois::Context& whois) override
@@ -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"));
diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp
index b06f357d0..2f9bd3a04 100644
--- a/src/modules/m_swhois.cpp
+++ b/src/modules/m_swhois.cpp
@@ -44,7 +44,8 @@ class CommandSwhois : public Command
, operblock(Creator, "swhois_operblock", ExtensionItem::EXT_USER)
, swhois(Creator, "swhois", ExtensionItem::EXT_USER, true)
{
- flags_needed = 'o'; syntax = "<nick> :<swhois>";
+ flags_needed = 'o';
+ syntax = "<nick> :<swhois>";
translation = { TR_NICK, TR_TEXT };
}
diff --git a/src/modules/m_vhost.cpp b/src/modules/m_vhost.cpp
index 32da8b45d..ae858ab68 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/usermanager.cpp b/src/usermanager.cpp
index 9ea2f2641..5dead741c 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 07c929c9b..c024ef366 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -90,7 +90,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)
@@ -343,8 +343,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();
}
@@ -1144,9 +1144,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;
@@ -1265,4 +1265,6 @@ void ConnectClass::Update(const ConnectClass* src)
limit = src->limit;
resolvehostnames = src->resolvehostnames;
ports = src->ports;
+ password = src->password;
+ passwordhash = src->passwordhash;
}
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;
}