diff options
| author | 2020-03-18 13:51:23 +0000 | |
|---|---|---|
| committer | 2020-03-18 13:51:23 +0000 | |
| commit | b9acde9aaf0ddae8b821b21821724adcdbea9359 (patch) | |
| tree | 7c76b8988dd9e31596ae2b114b15a762561e063d | |
| parent | Remove support for 0/1 in getBool. (diff) | |
| parent | Allow commands to override ERR_{NEEDSMOREPARAMS,NOTREGISTERED}. (diff) | |
Merge branch 'insp3' into master.
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 @@ -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; } |
