diff options
Diffstat (limited to 'src')
27 files changed, 207 insertions, 34 deletions
diff --git a/src/command_parse.cpp b/src/command_parse.cpp index c93dac65f..7998d9cc3 100644 --- a/src/command_parse.cpp +++ b/src/command_parse.cpp @@ -182,11 +182,21 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) /* find the command, check it exists */ Command* handler = GetHandler(command); + // Penalty to give if the command fails before the handler is executed + unsigned int failpenalty = 0; + /* Modify the user's penalty regardless of whether or not the command exists */ if (!user->HasPrivPermission("users/flood/no-throttle")) { // If it *doesn't* exist, give it a slightly heftier penalty than normal to deter flooding us crap - user->CommandFloodPenalty += handler ? handler->Penalty * 1000 : 2000; + unsigned int penalty = (handler ? handler->Penalty * 1000 : 2000); + user->CommandFloodPenalty += penalty; + + // Increase their penalty later if we fail and the command has 0 penalty by default (i.e. in Command::Penalty) to + // throttle sending ERR_* from the command parser. If the command does have a non-zero penalty then this is not + // needed because we've increased their penalty above. + if (penalty == 0) + failpenalty = 1000; } if (!handler) @@ -257,12 +267,14 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) { if (!user->IsModeSet(handler->flags_needed)) { + user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - You do not have the required operator privileges"); return; } if (!user->HasPermission(command)) { + user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Oper type %s does not have access to command %s", user->oper->name.c_str(), command.c_str()); return; @@ -272,6 +284,7 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) if ((user->registered == REG_ALL) && (!user->IsOper()) && (handler->IsDisabled())) { /* command is disabled! */ + user->CommandFloodPenalty += failpenalty; if (ServerInstance->Config->DisabledDontExist) { user->WriteNumeric(ERR_UNKNOWNCOMMAND, "%s :Unknown command", command.c_str()); @@ -291,6 +304,7 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) if (command_p.size() < handler->min_params) { + user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s :Not enough parameters.", command.c_str()); if ((ServerInstance->Config->SyntaxHints) && (user->registered == REG_ALL) && (handler->syntax.length())) user->WriteNumeric(RPL_SYNTAX, ":SYNTAX %s %s", handler->name.c_str(), handler->syntax.c_str()); @@ -299,6 +313,7 @@ void CommandParser::ProcessCommand(LocalUser *user, std::string &cmd) if ((user->registered != REG_ALL) && (!handler->WorksBeforeReg())) { + user->CommandFloodPenalty += failpenalty; user->WriteNumeric(ERR_NOTREGISTERED, "%s :You have not registered",command.c_str()); } else diff --git a/src/configreader.cpp b/src/configreader.cpp index d52f3de13..68495623c 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -53,6 +53,7 @@ static ConfigTag* CreateEmptyTag() ServerConfig::ServerConfig() : EmptyTag(CreateEmptyTag()) , Limits(EmptyTag) + , NoSnoticeStack(false) { RawLog = HideBans = HideSplits = UndernetMsgPrefix = false; WildcardIPv6 = InvBypassModes = true; @@ -575,7 +576,7 @@ void ServerConfig::Apply(ServerConfig* old, const std::string &useruid) errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl << "You will need to do this if you want clients to be able to connect!" << std::endl; - if (old) + if (old && valid) { // On first run, ports are bound later on FailedPortList pl; @@ -784,6 +785,7 @@ void ConfigReaderThread::Finish() * XXX: The order of these is IMPORTANT, do not reorder them without testing * thoroughly!!! */ + ServerInstance->Users.RehashCloneCounts(); ServerInstance->XLines->CheckELines(); ServerInstance->XLines->ApplyLines(); ChanModeReference ban(NULL, "ban"); diff --git a/src/coremods/core_dns.cpp b/src/coremods/core_dns.cpp index de8dedd4a..9aca8b338 100644 --- a/src/coremods/core_dns.cpp +++ b/src/coremods/core_dns.cpp @@ -33,6 +33,11 @@ using namespace DNS; */ class Packet : public Query { + static bool IsValidName(const std::string& name) + { + return (name.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-") == std::string::npos); + } + void PackName(unsigned char* output, unsigned short output_size, unsigned short& pos, const std::string& name) { if (pos + name.length() + 2 > output_size) @@ -183,6 +188,9 @@ class Packet : public Query case QUERY_PTR: { record.rdata = this->UnpackName(input, input_size, pos); + if (!IsValidName(record.rdata)) + throw Exception("Invalid name"); // XXX: Causes the request to time out + break; } default: diff --git a/src/coremods/core_info/cmd_motd.cpp b/src/coremods/core_info/cmd_motd.cpp index 2d396858f..57616094e 100644 --- a/src/coremods/core_info/cmd_motd.cpp +++ b/src/coremods/core_info/cmd_motd.cpp @@ -32,7 +32,13 @@ CommandMotd::CommandMotd(Module* parent) CmdResult CommandMotd::Handle (const std::vector<std::string>& parameters, User *user) { if (parameters.size() > 0 && parameters[0] != ServerInstance->Config->ServerName) + { + // Give extra penalty if a non-oper queries the /MOTD of a remote server + LocalUser* localuser = IS_LOCAL(user); + if ((localuser) && (!user->IsOper())) + localuser->CommandFloodPenalty += 2000; return CMD_SUCCESS; + } ConfigTag* tag = ServerInstance->Config->EmptyTag; LocalUser* localuser = IS_LOCAL(user); diff --git a/src/coremods/core_list.cpp b/src/coremods/core_list.cpp index 745f019f2..278e6044d 100644 --- a/src/coremods/core_list.cpp +++ b/src/coremods/core_list.cpp @@ -94,14 +94,15 @@ CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User // if the channel is not private/secret, OR the user is on the channel anyway bool n = (has_privs || chan->HasUser(user)); - if ((!n) && (chan->IsModeSet(privatemode))) + // If we're not in the channel and +s is set on it, we want to ignore it + if ((n) || (!chan->IsModeSet(secretmode))) { - /* Channel is +p and user is outside/not privileged */ - user->WriteNumeric(RPL_LIST, "* %ld :", users); - } - else - { - if ((n) || (!chan->IsModeSet(secretmode))) + if ((!n) && (chan->IsModeSet(privatemode))) + { + // Channel is private (+p) and user is outside/not privileged + user->WriteNumeric(RPL_LIST, "* %ld :", users); + } + else { /* User is in the channel/privileged, channel is not +s */ user->WriteNumeric(RPL_LIST, "%s %ld :[+%s] %s", chan->name.c_str(), users, chan->ChanModes(n), chan->topic.c_str()); diff --git a/src/coremods/core_reloadmodule.cpp b/src/coremods/core_reloadmodule.cpp index 1561131dc..7f0f15e77 100644 --- a/src/coremods/core_reloadmodule.cpp +++ b/src/coremods/core_reloadmodule.cpp @@ -65,7 +65,7 @@ CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameter if (m) { - ServerInstance->Modules->Reload(m, new ReloadModuleWorker(user->uuid, parameters[0])); + ServerInstance->Modules->Reload(m, (creator->dying ? NULL : new ReloadModuleWorker(user->uuid, parameters[0]))); return CMD_SUCCESS; } else diff --git a/src/coremods/core_stats.cpp b/src/coremods/core_stats.cpp index 997dd3afe..180ece9b3 100644 --- a/src/coremods/core_stats.cpp +++ b/src/coremods/core_stats.cpp @@ -58,7 +58,7 @@ static void GenerateStatsLl(User* user, string_list& results, char c) for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i) { LocalUser* u = *i; - results.push_back("211 "+user->nick+" "+u->nick+"["+u->ident+"@"+(c == 'l' ? u->dhost : u->GetIPString())+"] "+ConvToStr(u->eh.getSendQSize())+" "+ConvToStr(u->cmds_out)+" "+ConvToStr(u->bytes_out)+" "+ConvToStr(u->cmds_in)+" "+ConvToStr(u->bytes_in)+" "+ConvToStr(ServerInstance->Time() - u->age)); + results.push_back("211 "+user->nick+" "+u->nick+"["+u->ident+"@"+(c == 'l' ? u->dhost : u->GetIPString())+"] "+ConvToStr(u->eh.getSendQSize())+" "+ConvToStr(u->cmds_out)+" "+ConvToStr(u->bytes_out)+" "+ConvToStr(u->cmds_in)+" "+ConvToStr(u->bytes_in)+" "+ConvToStr(ServerInstance->Time() - u->signon)); } } @@ -378,7 +378,13 @@ void CommandStats::DoStats(char statschar, User* user, string_list &results) CmdResult CommandStats::Handle (const std::vector<std::string>& parameters, User *user) { if (parameters.size() > 1 && parameters[1] != ServerInstance->Config->ServerName) + { + // Give extra penalty if a non-oper does /STATS <remoteserver> + LocalUser* localuser = IS_LOCAL(user); + if ((localuser) && (!user->IsOper())) + localuser->CommandFloodPenalty += 2000; return CMD_SUCCESS; + } string_list values; char search = parameters[0][0]; DoStats(search, user, values); diff --git a/src/coremods/core_user/cmd_user.cpp b/src/coremods/core_user/cmd_user.cpp index d593d7f4b..cbf4f5e08 100644 --- a/src/coremods/core_user/cmd_user.cpp +++ b/src/coremods/core_user/cmd_user.cpp @@ -58,6 +58,7 @@ CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, L else { user->WriteNumeric(ERR_ALREADYREGISTERED, ":You may not reregister"); + user->CommandFloodPenalty += 1000; return CMD_FAILURE; } diff --git a/src/coremods/core_user/core_user.cpp b/src/coremods/core_user/core_user.cpp index ffa6aa2ff..dd778548a 100644 --- a/src/coremods/core_user/core_user.cpp +++ b/src/coremods/core_user/core_user.cpp @@ -45,6 +45,7 @@ class CommandPass : public SplitCommand // Check to make sure they haven't registered -- Fix by FCS if (user->registered == REG_ALL) { + user->CommandFloodPenalty += 1000; user->WriteNumeric(ERR_ALREADYREGISTERED, ":You may not reregister"); return CMD_FAILURE; } @@ -64,7 +65,6 @@ class CommandPing : public Command CommandPing(Module* parent) : Command(parent, "PING", 1, 2) { - Penalty = 0; syntax = "<servername> [:<servername>]"; } @@ -102,8 +102,15 @@ class CommandPong : public Command CmdResult Handle(const std::vector<std::string>& parameters, User* user) { // set the user as alive so they survive to next ping - if (IS_LOCAL(user)) - IS_LOCAL(user)->lastping = 1; + LocalUser* localuser = IS_LOCAL(user); + if (localuser) + { + // Increase penalty unless we've sent a PING and this is the reply + if (localuser->lastping) + localuser->CommandFloodPenalty += 1000; + else + localuser->lastping = 1; + } return CMD_SUCCESS; } }; diff --git a/src/coremods/core_userhost.cpp b/src/coremods/core_userhost.cpp index a67824194..eae6e51ce 100644 --- a/src/coremods/core_userhost.cpp +++ b/src/coremods/core_userhost.cpp @@ -24,10 +24,15 @@ */ class CommandUserhost : public Command { + UserModeReference hideopermode; + public: /** Constructor for userhost. */ - CommandUserhost ( Module* parent) : Command(parent,"USERHOST", 1, 5) { + CommandUserhost(Module* parent) + : Command(parent,"USERHOST", 1) + , hideopermode(parent, "hideoper") + { syntax = "<nick> [<nick> ...]"; } /** Handle command. @@ -44,7 +49,11 @@ CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, U std::string retbuf = "302 " + user->nick + " :"; - for (unsigned int i = 0; i < parameters.size(); i++) + unsigned int max = parameters.size(); + if (max > 5) + max = 5; + + for (unsigned int i = 0; i < max; i++) { User *u = ServerInstance->FindNickOnly(parameters[i]); @@ -53,7 +62,11 @@ CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, U retbuf += u->nick; if (u->IsOper()) - retbuf += '*'; + { + // XXX: +H hidden opers must not be shown as opers + if ((u == user) || (has_privs) || (!u->IsModeSet(hideopermode))) + retbuf += '*'; + } retbuf += '='; retbuf += (u->IsAway() ? '-' : '+'); diff --git a/src/coremods/core_who.cpp b/src/coremods/core_who.cpp index 39ea347dc..8b9258d71 100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@ -144,7 +144,7 @@ bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext) long seconds = InspIRCd::Duration(matchtext); // Okay, so time matching, we want all users connected `seconds' ago - if (user->age >= ServerInstance->Time() - seconds) + if (user->signon >= ServerInstance->Time() - seconds) match = true; } diff --git a/src/hashcomp.cpp b/src/hashcomp.cpp index 42e25f8f6..35e5f3671 100644 --- a/src/hashcomp.cpp +++ b/src/hashcomp.cpp @@ -153,7 +153,7 @@ unsigned const char rfc_case_sensitive_map[256] = { size_t CoreExport irc::hash::operator()(const irc::string &s) const { - register size_t t = 0; + size_t t = 0; for (irc::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */ t = 5 * t + national_case_insensitive_map[(unsigned char)*x]; return t; @@ -196,7 +196,7 @@ size_t irc::insensitive::operator()(const std::string &s) const * only with *x replaced with national_case_insensitive_map[*x]. * This avoids a copy to use hash<const char*> */ - register size_t t = 0; + size_t t = 0; for (std::string::const_iterator x = s.begin(); x != s.end(); ++x) /* ++x not x++, as its faster */ t = 5 * t + national_case_insensitive_map[(unsigned char)*x]; return t; diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp index 184013a4e..fc6161e31 100644 --- a/src/modmanager_dynamic.cpp +++ b/src/modmanager_dynamic.cpp @@ -31,7 +31,10 @@ bool ModuleManager::Load(const std::string& filename, bool defer) { /* Don't allow people to specify paths for modules, it doesn't work as expected */ if (filename.find('/') != std::string::npos) + { + LastModuleError = "You can't load modules with a path: " + filename; return false; + } const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename); diff --git a/src/modules/m_abbreviation.cpp b/src/modules/m_abbreviation.cpp index 77d86cb31..d2fa09c4e 100644 --- a/src/modules/m_abbreviation.cpp +++ b/src/modules/m_abbreviation.cpp @@ -67,7 +67,7 @@ class ModuleAbbreviation : public Module /* Ambiguous command, list the matches */ if (!matchlist.empty()) { - user->WriteNumeric(420, ":Ambiguous abbreviation, posssible matches: %s%s", foundcommand.c_str(), matchlist.c_str()); + user->WriteNumeric(420, ":Ambiguous abbreviation, possible matches: %s%s", foundcommand.c_str(), matchlist.c_str()); return MOD_RES_DENY; } diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index 8ae30bfed..6f9c32fb1 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -73,8 +73,10 @@ class CommandCheck : public Command { char timebuf[60]; struct tm *mytime = gmtime(&time); - strftime(timebuf, 59, "%Y-%m-%d %H:%M:%S UTC (%s)", mytime); - return std::string(timebuf); + strftime(timebuf, 59, "%Y-%m-%d %H:%M:%S UTC (", mytime); + std::string ret(timebuf); + ret.append(ConvToStr(time)).push_back(')'); + return ret; } void dumpExt(User* user, const std::string& checkstr, Extensible* ext) diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp index 2b8d1306c..f011fa449 100644 --- a/src/modules/m_dccallow.cpp +++ b/src/modules/m_dccallow.cpp @@ -318,6 +318,9 @@ class ModuleDCCAllow : public Module while (ss >> buf) tokens.push_back(buf); + if (tokens.size() < 2) + return MOD_RES_PASSTHRU; + irc::string type = tokens[1].c_str(); ConfigTag* conftag = ServerInstance->Config->ConfValue("dccallow"); @@ -325,6 +328,9 @@ class ModuleDCCAllow : public Module if (type == "SEND") { + if (tokens.size() < 3) + return MOD_RES_PASSTHRU; + std::string defaultaction = conftag->getString("action"); std::string filename = tokens[2]; diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index 8ee8472e6..a3f3242f0 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -155,7 +155,7 @@ class CommandGreloadmodule : public Command if (m) { GReloadModuleWorker* worker = NULL; - if (m != creator) + if ((m != creator) && (!creator->dying)) worker = new GReloadModuleWorker(user->nick, user->uuid, parameters[0]); ServerInstance->Modules->Reload(m, worker); } diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 5b226f3b8..81b9b888f 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -68,7 +68,11 @@ class ModuleHideOper : public Module if (user->IsModeSet(hm) && !source->HasPrivPermission("users/auspex")) { // hide the "*" that marks the user as an oper from the /WHO line - std::string::size_type pos = line.find("*"); + std::string::size_type spcolon = line.find(" :"); + if (spcolon == std::string::npos) + return; // Another module hid the user completely + std::string::size_type sp = line.rfind(' ', spcolon-1); + std::string::size_type pos = line.find('*', sp); if (pos != std::string::npos) line.erase(pos, 1); // hide the line completely if doing a "/who * o" query diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index e09ca3fa2..aa83b120c 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -407,6 +407,20 @@ class ModuleHttpServer : public Module return MOD_RES_ALLOW; } + void OnUnloadModule(Module* mod) + { + for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i) + { + HttpServerSocket* sock = *i; + ++i; + if (sock->GetIOHook() && sock->GetIOHook()->prov->creator == mod) + { + sock->cull(); + delete sock; + } + } + } + CullResult cull() CXX11_OVERRIDE { for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i) diff --git a/src/modules/m_md5.cpp b/src/modules/m_md5.cpp index 6e6f5006f..6cec05a18 100644 --- a/src/modules/m_md5.cpp +++ b/src/modules/m_md5.cpp @@ -154,7 +154,7 @@ class MD5Provider : public HashProvider void MD5Transform(word32 buf[4], word32 const in[16]) { - register word32 a, b, c, d; + word32 a, b, c, d; a = buf[0]; b = buf[1]; diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp index 4c63e53d1..51281a528 100644 --- a/src/modules/m_operprefix.cpp +++ b/src/modules/m_operprefix.cpp @@ -72,6 +72,20 @@ class ModuleOperPrefixMode : public Module return MOD_RES_PASSTHRU; } + void OnPostJoin(Membership* memb) + { + if ((!IS_LOCAL(memb->user)) || (!memb->user->IsOper()) || (memb->user->IsModeSet(hideopermode))) + return; + + if (memb->hasMode(opm.GetModeChar())) + return; + + // The user was force joined and OnUserPreJoin() did not run. Set the operprefix now. + Modes::ChangeList changelist; + changelist.push_add(&opm, memb->user->nick); + ServerInstance->Modes.Process(ServerInstance->FakeClient, memb->chan, NULL, changelist); + } + void SetOperPrefix(User* user, bool add) { Modes::ChangeList changelist; diff --git a/src/modules/m_sasl.cpp b/src/modules/m_sasl.cpp index c96b87034..341b3aea7 100644 --- a/src/modules/m_sasl.cpp +++ b/src/modules/m_sasl.cpp @@ -96,6 +96,9 @@ class SaslAuthenticator if (msg[0] != this->agent) return this->state; + if (msg.size() < 4) + return this->state; + if (msg[2] == "C") this->user->Write("AUTHENTICATE %s", msg[3].c_str()); else if (msg[2] == "D") @@ -285,7 +288,7 @@ class ModuleSASL : public Module Version GetVersion() CXX11_OVERRIDE { - return Version("Provides support for IRC Authentication Layer (aka: atheme SASL) via AUTHENTICATE.",VF_VENDOR); + return Version("Provides support for IRC Authentication Layer (aka: SASL) via AUTHENTICATE.", VF_VENDOR); } }; diff --git a/src/modules/m_spanningtree/fjoin.cpp b/src/modules/m_spanningtree/fjoin.cpp index 25c1f6678..e29aa09d7 100644 --- a/src/modules/m_spanningtree/fjoin.cpp +++ b/src/modules/m_spanningtree/fjoin.cpp @@ -129,8 +129,8 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params) time_t ourTS = chan->age; if (TS != ourTS) { - ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %lu", - chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (unsigned long)(ourTS - TS)); + ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %ld", + chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (long)(ourTS - TS)); /* If our TS is less than theirs, we dont accept their modes */ if (ourTS < TS) { diff --git a/src/modules/m_spanningtree/treeserver.cpp b/src/modules/m_spanningtree/treeserver.cpp index d0c6401cd..afd86c0ce 100644 --- a/src/modules/m_spanningtree/treeserver.cpp +++ b/src/modules/m_spanningtree/treeserver.cpp @@ -40,7 +40,7 @@ TreeServer::TreeServer() , Socket(NULL), sid(ServerInstance->Config->GetSID()), behind_bursting(0), isdead(false) , pingtimer(this) , ServerUser(ServerInstance->FakeClient) - , age(ServerInstance->Time()), UserCount(ServerInstance->Users.GetLocalUsers().size()) + , age(ServerInstance->Time()), UserCount(ServerInstance->Users.LocalUserCount()) , OperCount(0), rtt(0), StartBurst(0), Hidden(false) { AddHashEntry(); diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp index 803156446..8196d37ba 100644 --- a/src/modules/m_timedbans.cpp +++ b/src/modules/m_timedbans.cpp @@ -21,6 +21,7 @@ #include "inspircd.h" +#include "listmode.h" /** Holds a timed ban */ @@ -30,6 +31,7 @@ class TimedBan std::string channel; std::string mask; time_t expire; + Channel* chan; }; typedef std::vector<TimedBan> timedbans; @@ -39,8 +41,28 @@ timedbans TimedBanList; */ class CommandTban : public Command { + ChanModeReference banmode; + + bool IsBanSet(Channel* chan, const std::string& mask) + { + ListModeBase* banlm = static_cast<ListModeBase*>(*banmode); + const ListModeBase::ModeList* bans = banlm->GetList(chan); + if (bans) + { + for (ListModeBase::ModeList::const_iterator i = bans->begin(); i != bans->end(); ++i) + { + const ListModeBase::ListItem& ban = *i; + if (!strcasecmp(ban.mask.c_str(), mask.c_str())) + return true; + } + } + + return false; + } + public: CommandTban(Module* Creator) : Command(Creator,"TBAN", 3) + , banmode(Creator, "ban") { syntax = "<channel> <duration> <banmask>"; } @@ -75,6 +97,12 @@ class CommandTban : public Command if (!isextban && !InspIRCd::IsValidMask(mask)) mask.append("!*@*"); + if (IsBanSet(channel, mask)) + { + user->WriteNotice("Ban already set"); + return CMD_FAILURE; + } + Modes::ChangeList setban; setban.push_add(ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL), mask); // Pass the user (instead of ServerInstance->FakeClient) to ModeHandler::Process() to @@ -90,6 +118,7 @@ class CommandTban : public Command T.channel = channelname; T.mask = mask; T.expire = expire + (IS_REMOTE(user) ? 5 : 0); + T.chan = channel; TimedBanList.push_back(T); // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above @@ -134,6 +163,22 @@ class BanWatcher : public ModeWatcher } }; +class ChannelMatcher +{ + Channel* const chan; + + public: + ChannelMatcher(Channel* ch) + : chan(ch) + { + } + + bool operator()(const TimedBan& tb) const + { + return (tb.chan == chan); + } +}; + class ModuleTimedBans : public Module { CommandTban cmd; @@ -179,6 +224,12 @@ class ModuleTimedBans : public Module } } + void OnChannelDelete(Channel* chan) + { + // Remove all timed bans affecting the channel from internal bookkeeping + TimedBanList.erase(std::remove_if(TimedBanList.begin(), TimedBanList.end(), ChannelMatcher(chan)), TimedBanList.end()); + } + Version GetVersion() CXX11_OVERRIDE { return Version("Adds timed bans", VF_COMMON | VF_VENDOR); diff --git a/src/threadengines/threadengine_pthread.cpp b/src/threadengines/threadengine_pthread.cpp index 6456d6df5..3249f442b 100644 --- a/src/threadengines/threadengine_pthread.cpp +++ b/src/threadengines/threadengine_pthread.cpp @@ -95,7 +95,7 @@ SocketThread::SocketThread() signal.sock = NULL; int fd = eventfd(0, EFD_NONBLOCK); if (fd < 0) - throw new CoreException("Could not create pipe " + std::string(strerror(errno))); + throw CoreException("Could not create pipe " + std::string(strerror(errno))); signal.sock = new ThreadSignalSocket(this, fd); } #else @@ -148,7 +148,7 @@ SocketThread::SocketThread() signal.sock = NULL; int fds[2]; if (pipe(fds)) - throw new CoreException("Could not create pipe " + std::string(strerror(errno))); + throw CoreException("Could not create pipe " + std::string(strerror(errno))); signal.sock = new ThreadSignalSocket(this, fds[0], fds[1]); } #endif diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 1966c9b47..4ebc3b583 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -93,7 +93,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs this->clientlist[New->nick] = New; New->registered = REG_NONE; - New->signon = ServerInstance->Time() + ServerInstance->Config->dns_timeout; + New->signon = ServerInstance->Time(); New->lastping = 1; this->AddClone(New); @@ -254,6 +254,18 @@ void UserManager::RemoveCloneCounts(User *user) } } +void UserManager::RehashCloneCounts() +{ + clonemap.clear(); + + const user_hash& hash = ServerInstance->Users.GetUsers(); + for (user_hash::const_iterator i = hash.begin(); i != hash.end(); ++i) + { + User* u = i->second; + AddClone(u); + } +} + const UserManager::CloneCounts& UserManager::GetCloneCounts(User* user) const { CloneMap::const_iterator it = clonemap.find(user->GetCIDRMask()); @@ -348,10 +360,15 @@ void UserManager::DoBackgroundUserStuff() curr->FullConnect(); continue; } + + // If the user has been quit in OnCheckReady then we shouldn't + // quit them again for having a registration timeout. + if (curr->quitting) + continue; break; } - if (curr->registered != REG_ALL && (ServerInstance->Time() > (curr->age + curr->MyClass->GetRegTimeout()))) + if (curr->registered != REG_ALL && curr->MyClass && (ServerInstance->Time() > (curr->signon + curr->MyClass->GetRegTimeout()))) { /* * registration timeout -- didnt send USER/NICK/HOST |