summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/conf/inspircd.conf.example6
-rw-r--r--include/modules.h5
-rw-r--r--include/socketengine.h18
-rwxr-xr-xmodulemanager2
-rw-r--r--src/channels.cpp6
-rw-r--r--src/commands/cmd_invite.cpp16
-rw-r--r--src/configreader.cpp3
-rw-r--r--src/inspsocket.cpp6
-rw-r--r--src/listensocket.cpp3
-rw-r--r--src/modmanager_dynamic.cpp1
-rw-r--r--src/modmanager_static.cpp2
-rw-r--r--src/modules.cpp4
-rw-r--r--src/modules/extra/m_ssl_gnutls.cpp39
-rw-r--r--src/modules/m_callerid.cpp60
-rw-r--r--src/modules/m_filter.cpp74
-rw-r--r--src/modules/m_ident.cpp1
-rw-r--r--src/modules/m_kicknorejoin.cpp59
-rw-r--r--src/modules/m_nonotice.cpp5
-rw-r--r--src/modules/m_permchannels.cpp40
-rw-r--r--src/modules/m_rline.cpp48
-rw-r--r--src/modules/m_services_account.cpp16
-rw-r--r--src/modules/m_spanningtree/main.cpp2
-rw-r--r--src/modules/m_spanningtree/server.cpp67
-rw-r--r--src/modules/m_spanningtree/treesocket.h11
-rw-r--r--src/modules/m_spanningtree/treesocket2.cpp12
-rw-r--r--src/socketengine.cpp5
-rw-r--r--src/usermanager.cpp8
-rw-r--r--src/users.cpp9
28 files changed, 378 insertions, 150 deletions
diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example
index e0ed5e67e..eeed82237 100644
--- a/docs/conf/inspircd.conf.example
+++ b/docs/conf/inspircd.conf.example
@@ -646,6 +646,12 @@
# to 5, while others (such as linux and *BSD) default to 128.
somaxconn="128"
+ # limitsomaxconn: By default, somaxconn (see above) is limited to a
+ # safe maximum value in the 2.0 branch for compatibility reasons.
+ # This setting can be used to disable this limit, forcing InspIRCd
+ # to use the value specifed above.
+ limitsomaxconn="true"
+
# softlimit: This optional feature allows a defined softlimit for
# connections. If defined, it sets a soft max connections value.
softlimit="12800"
diff --git a/include/modules.h b/include/modules.h
index 0b91e6048..72ee2683d 100644
--- a/include/modules.h
+++ b/include/modules.h
@@ -391,6 +391,11 @@ class CoreExport Module : public classbase, public usecountbase
*/
DLLManager* ModuleDLLManager;
+ /** If true, this module will be unloaded soon, further unload attempts will fail
+ * Value is used by the ModuleManager internally, you should not modify it
+ */
+ bool dying;
+
/** Default constructor.
* Creates a module class. Don't do any type of hook registration or checks
* for other modules here; do that in init().
diff --git a/include/socketengine.h b/include/socketengine.h
index fd199c324..8e4c3dfc9 100644
--- a/include/socketengine.h
+++ b/include/socketengine.h
@@ -488,6 +488,24 @@ public:
/** Get data transfer statistics, kilobits per second in and out and total.
*/
void GetStats(float &kbitpersec_in, float &kbitpersec_out, float &kbitpersec_total);
+
+ /** Should we ignore the error in errno?
+ * Checks EAGAIN and WSAEWOULDBLOCK
+ */
+ static bool IgnoreError();
};
+inline bool SocketEngine::IgnoreError()
+{
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
+ return true;
+
+#ifdef _WIN32
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ return true;
+#endif
+
+ return false;
+}
+
SocketEngine* CreateSocketEngine();
diff --git a/modulemanager b/modulemanager
index d1212faf5..7884654af 100755
--- a/modulemanager
+++ b/modulemanager
@@ -262,7 +262,7 @@ sub resolve_deps {
}
}
-my $action = lc shift @ARGV;
+my $action = $#ARGV > 0 ? lc shift @ARGV : 'help';
if ($action eq 'install') {
for my $mod (@ARGV) {
diff --git a/src/channels.cpp b/src/channels.cpp
index edb4d056a..9e9ad670a 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -34,12 +34,10 @@ static ModeReference ban(NULL, "ban");
Channel::Channel(const std::string &cname, time_t ts)
{
- chan_hash::iterator findchan = ServerInstance->chanlist->find(cname);
- if (findchan != ServerInstance->chanlist->end())
+ if (!ServerInstance->chanlist->insert(std::make_pair(cname, this)).second)
throw CoreException("Cannot create duplicate channel " + cname);
- (*(ServerInstance->chanlist))[cname.c_str()] = this;
- this->name.assign(cname, 0, ServerInstance->Config->Limits.ChanMax);
+ this->name = cname;
this->age = ts ? ts : ServerInstance->Time();
topicset = 0;
diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp
index 6e5aead12..7221521de 100644
--- a/src/commands/cmd_invite.cpp
+++ b/src/commands/cmd_invite.cpp
@@ -72,16 +72,16 @@ CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, Use
return CMD_FAILURE;
}
- if (c->HasUser(u))
- {
- user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str());
- return CMD_FAILURE;
- }
-
if ((IS_LOCAL(user)) && (!c->HasUser(user)))
- {
+ {
user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str());
- return CMD_FAILURE;
+ return CMD_FAILURE;
+ }
+
+ if (c->HasUser(u))
+ {
+ user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str());
+ return CMD_FAILURE;
}
FIRST_MOD_RESULT(OnUserPreInvite, MOD_RESULT, (user,u,c,timeout));
diff --git a/src/configreader.cpp b/src/configreader.cpp
index 1b565c7f7..dcf4b7162 100644
--- a/src/configreader.cpp
+++ b/src/configreader.cpp
@@ -431,7 +431,8 @@ void ServerConfig::Fill()
NoSnoticeStack = options->getBool("nosnoticestack", false);
range(SoftLimit, 10, ServerInstance->SE->GetMaxFds(), ServerInstance->SE->GetMaxFds(), "<performance:softlimit>");
- range(MaxConn, 0, SOMAXCONN, SOMAXCONN, "<performance:somaxconn>");
+ if (ConfValue("performance")->getBool("limitsomaxconn", true))
+ range(MaxConn, 0, SOMAXCONN, SOMAXCONN, "<performance:somaxconn>");
range(MaxTargets, 1, 31, 20, "<security:maxtargets>");
range(NetBufferSize, 1024, 65534, 10240, "<performance:netbuffersize>");
diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp
index b1bfaa9fd..34d7d3f8c 100644
--- a/src/inspsocket.cpp
+++ b/src/inspsocket.cpp
@@ -200,7 +200,7 @@ void StreamSocket::DoRead()
error = "Connection closed";
ServerInstance->SE->ChangeEventMask(this, FD_WANT_NO_READ | FD_WANT_NO_WRITE);
}
- else if (errno == EAGAIN)
+ else if (SocketEngine::IgnoreError())
{
ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_READ | FD_READ_WILL_BLOCK);
}
@@ -291,7 +291,7 @@ void StreamSocket::DoWrite()
}
else if (rv < 0)
{
- if (errno == EAGAIN || errno == EINTR)
+ if (errno == EINTR || SocketEngine::IgnoreError())
ServerInstance->SE->ChangeEventMask(this, FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK);
else
SetError(strerror(errno));
@@ -388,7 +388,7 @@ void StreamSocket::DoWrite()
{
error = "Connection closed";
}
- else if (errno == EAGAIN)
+ else if (SocketEngine::IgnoreError())
{
eventChange = FD_WANT_FAST_WRITE | FD_WRITE_WILL_BLOCK;
}
diff --git a/src/listensocket.cpp b/src/listensocket.cpp
index 2f25c5493..8ac8babf3 100644
--- a/src/listensocket.cpp
+++ b/src/listensocket.cpp
@@ -75,7 +75,8 @@ ListenSocket::~ListenSocket()
{
ServerInstance->SE->DelFd(this);
ServerInstance->Logs->Log("SOCKET", LOG_DEBUG,"Shut down listener on fd %d", this->fd);
- if (ServerInstance->SE->Shutdown(this, 2) || ServerInstance->SE->Close(this))
+ ServerInstance->SE->Shutdown(this, 2);
+ if (ServerInstance->SE->Close(this) != 0)
ServerInstance->Logs->Log("SOCKET", LOG_DEBUG,"Failed to cancel listener: %s", strerror(errno));
this->fd = -1;
}
diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp
index 9935fb61a..a153accbb 100644
--- a/src/modmanager_dynamic.cpp
+++ b/src/modmanager_dynamic.cpp
@@ -65,6 +65,7 @@ bool ModuleManager::Load(const std::string& filename, bool defer)
{
newmod->ModuleSourceFile = filename;
newmod->ModuleDLLManager = newhandle;
+ newmod->dying = false;
Modules[filename] = newmod;
std::string version = newhandle->GetVersion();
if (defer)
diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp
index 23f30e1df..4c4624195 100644
--- a/src/modmanager_static.cpp
+++ b/src/modmanager_static.cpp
@@ -93,6 +93,7 @@ bool ModuleManager::Load(const std::string& name, bool defer)
mod = (*it->second->init)();
mod->ModuleSourceFile = name;
mod->ModuleDLLManager = NULL;
+ mod->dying = false;
Modules[name] = mod;
if (defer)
{
@@ -183,6 +184,7 @@ void ModuleManager::LoadAll()
{
Load("cmd_all", true);
Load("cmd_whowas.so", true);
+ Load("cmd_lusers.so", true);
ConfigTagList tags = ServerInstance->Config->ConfTags("module");
for(ConfigIter i = tags.first; i != tags.second; ++i)
diff --git a/src/modules.cpp b/src/modules.cpp
index c9118d1a7..63e1118d9 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -327,7 +327,7 @@ bool ModuleManager::CanUnload(Module* mod)
{
std::map<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile);
- if (modfind == Modules.end() || modfind->second != mod)
+ if ((modfind == Modules.end()) || (modfind->second != mod) || (mod->dying))
{
LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!";
ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
@@ -339,6 +339,8 @@ bool ModuleManager::CanUnload(Module* mod)
ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError);
return false;
}
+
+ mod->dying = true;
return true;
}
diff --git a/src/modules/extra/m_ssl_gnutls.cpp b/src/modules/extra/m_ssl_gnutls.cpp
index 1caacaa0f..00dff68e6 100644
--- a/src/modules/extra/m_ssl_gnutls.cpp
+++ b/src/modules/extra/m_ssl_gnutls.cpp
@@ -86,6 +86,12 @@ static ssize_t gnutls_pull_wrapper(gnutls_transport_ptr_t user_wrap, void* buffe
return -1;
}
int rv = ServerInstance->SE->Recv(user, reinterpret_cast<char *>(buffer), size, 0);
+ if (rv < 0)
+ {
+ /* On Windows we need to set errno for gnutls */
+ if (SocketEngine::IgnoreError())
+ errno = EAGAIN;
+ }
if (rv < (int)size)
ServerInstance->SE->ChangeEventMask(user, FD_READ_WILL_BLOCK);
return rv;
@@ -100,6 +106,12 @@ static ssize_t gnutls_push_wrapper(gnutls_transport_ptr_t user_wrap, const void*
return -1;
}
int rv = ServerInstance->SE->Send(user, reinterpret_cast<const char *>(buffer), size, 0);
+ if (rv < 0)
+ {
+ /* On Windows we need to set errno for gnutls */
+ if (SocketEngine::IgnoreError())
+ errno = EAGAIN;
+ }
if (rv < (int)size)
ServerInstance->SE->ChangeEventMask(user, FD_WRITE_WILL_BLOCK);
return rv;
@@ -322,6 +334,7 @@ class ModuleSSLGnuTLS : public Module
{
gnutls_dh_params_deinit(dh_params);
dh_alloc = false;
+ dh_params = NULL;
}
if (cred_alloc)
@@ -409,10 +422,30 @@ class ModuleSSLGnuTLS : public Module
ret = gnutls_dh_params_init(&dh_params);
dh_alloc = (ret >= 0);
if (!dh_alloc)
- ServerInstance->Logs->Log("m_ssl_gnutls",LOG_DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret));
+ {
+ ServerInstance->Logs->Log("m_ssl_gnutls", LOG_DEFAULT, "m_ssl_gnutls.so: Failed to initialise DH parameters: %s", gnutls_strerror(ret));
+ return;
+ }
- // This may be on a large (once a day or week) timer eventually.
- GenerateDHParams();
+ std::string dhfile = Conf->getString("dhfile");
+ if (!dhfile.empty())
+ {
+ // Try to load DH params from file
+ reader.LoadFile(dhfile);
+ std::string dhstring = reader.Contents();
+ gnutls_datum_t dh_datum = { (unsigned char*)dhstring.data(), static_cast<unsigned int>(dhstring.length()) };
+
+ if ((ret = gnutls_dh_params_import_pkcs3(dh_params, &dh_datum, GNUTLS_X509_FMT_PEM)) < 0)
+ {
+ // File unreadable or GnuTLS was unhappy with the contents, generate the DH primes now
+ ServerInstance->Logs->Log("m_ssl_gnutls", LOG_DEFAULT, "m_ssl_gnutls.so: Generating DH parameters because I failed to load them from file '%s': %s", dhfile.c_str(), gnutls_strerror(ret));
+ GenerateDHParams();
+ }
+ }
+ else
+ {
+ GenerateDHParams();
+ }
}
void GenerateDHParams()
diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp
index e8448bc91..3bc9583cc 100644
--- a/src/modules/m_callerid.cpp
+++ b/src/modules/m_callerid.cpp
@@ -38,26 +38,6 @@ class callerid_data
std::list<callerid_data *> wholistsme;
callerid_data() : lastnotify(0) { }
- callerid_data(const std::string& str)
- {
- irc::commasepstream s(str);
- std::string tok;
- if (s.GetToken(tok))
- {
- lastnotify = ConvToInt(tok);
- }
- while (s.GetToken(tok))
- {
- if (tok.empty())
- {
- continue;
- }
-
- User *u = ServerInstance->FindNick(tok);
- if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u)))
- accepting.insert(u);
- }
- }
std::string ToString(SerializeFormat format) const
{
@@ -88,8 +68,31 @@ struct CallerIDExtInfo : public ExtensionItem
void unserialize(SerializeFormat format, Extensible* container, const std::string& value)
{
- callerid_data* dat = new callerid_data(value);
- set_raw(container, dat);
+ callerid_data* dat = new callerid_data;
+ irc::commasepstream s(value);
+ std::string tok;
+ if (s.GetToken(tok))
+ dat->lastnotify = ConvToInt(tok);
+
+ while (s.GetToken(tok))
+ {
+ if (tok.empty())
+ continue;
+
+ User *u = ServerInstance->FindNick(tok);
+ if ((u) && (u->registered == REG_ALL) && (!u->quitting) && (!IS_SERVER(u)))
+ {
+ if (dat->accepting.insert(u).second)
+ {
+ callerid_data* other = this->get(u, true);
+ other->wholistsme.push_back(dat);
+ }
+ }
+ }
+
+ void* old = set_raw(container, dat);
+ if (old)
+ this->free(old);
}
callerid_data* get(User* user, bool create)
@@ -113,11 +116,16 @@ struct CallerIDExtInfo : public ExtensionItem
callerid_data *targ = this->get(*it, false);
if (!targ)
+ {
+ ServerInstance->Logs->Log("m_callerid", LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (1)");
continue; // shouldn't happen, but oh well.
+ }
std::list<callerid_data*>::iterator it2 = std::find(targ->wholistsme.begin(), targ->wholistsme.end(), dat);
if (it2 != targ->wholistsme.end())
targ->wholistsme.erase(it2);
+ else
+ ServerInstance->Logs->Log("m_callerid", LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (2)");
}
delete dat;
}
@@ -277,6 +285,7 @@ public:
if (!dat2)
{
// How the fuck is this possible.
+ ServerInstance->Logs->Log("m_callerid", LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (3)");
return false;
}
@@ -284,6 +293,9 @@ public:
if (it != dat2->wholistsme.end())
// Found me!
dat2->wholistsme.erase(it);
+ else
+ ServerInstance->Logs->Log("m_callerid", LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (4)");
+
user->WriteServ("NOTICE %s :%s is no longer on your accept list", user->nick.c_str(), whotoremove->nick.c_str());
return true;
@@ -320,6 +332,8 @@ class ModuleCallerID : public Module
if (it2 != dat->accepting.end())
dat->accepting.erase(it2);
+ else
+ ServerInstance->Logs->Log("m_callerid", LOG_DEFAULT, "ERROR: Inconsistency detected in callerid state, please report (5)");
}
userdata->wholistsme.clear();
@@ -354,7 +368,7 @@ public:
ModResult PreText(User* user, User* dest, std::string& text)
{
- if (!dest->IsModeSet('g'))
+ if (!dest->IsModeSet('g') || (user == dest))
return MOD_RES_PASSTHRU;
if (operoverride && user->IsOper())
diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp
index 027222b3a..8bfefd6eb 100644
--- a/src/modules/m_filter.cpp
+++ b/src/modules/m_filter.cpp
@@ -165,19 +165,22 @@ class ImplFilter : public FilterResult
class ModuleFilter : public Module
{
+ bool initing;
+ RegexFactory* factory;
+ void FreeFilters();
+
public:
CommandFilter filtcommand;
dynamic_reference<RegexFactory> RegexEngine;
std::vector<ImplFilter> filters;
- const char *error;
- int erroffset;
int flags;
std::set<std::string> exemptfromfilter; // List of channel names excluded from filtering.
ModuleFilter();
void init();
+ CullResult cull();
ModResult OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
FilterResult* FilterMatch(User* user, const std::string &text, int flags);
bool DeleteFilter(const std::string &freeform);
@@ -191,6 +194,7 @@ class ModuleFilter : public Module
void OnDecodeMetaData(Extensible* target, const std::string &extname, const std::string &extdata);
ModResult OnStats(char symbol, User* user, string_list &results);
ModResult OnPreCommand(std::string &command, std::vector<std::string> &parameters, LocalUser *user, bool validated, const std::string &original_line);
+ void OnUnloadModule(Module* mod);
bool AppliesToMe(User* user, FilterResult* filter, int flags);
void ReadFilters();
static bool StringToFilterAction(const std::string& str, FilterAction& fa);
@@ -292,18 +296,33 @@ bool ModuleFilter::AppliesToMe(User* user, FilterResult* filter, int iflags)
return true;
}
-ModuleFilter::ModuleFilter() : filtcommand(this), RegexEngine(this, "regex")
+ModuleFilter::ModuleFilter()
+ : initing(true), filtcommand(this), RegexEngine(this, "regex")
{
}
void ModuleFilter::init()
{
ServerInstance->Modules->AddService(filtcommand);
- Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash };
+ Implementation eventlist[] = { I_OnPreCommand, I_OnStats, I_OnSyncNetwork, I_OnDecodeMetaData, I_OnUserPreMessage, I_OnUserPreNotice, I_OnRehash, I_OnUnloadModule };
ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
OnRehash(NULL);
}
+CullResult ModuleFilter::cull()
+{
+ FreeFilters();
+ return Module::cull();
+}
+
+void ModuleFilter::FreeFilters()
+{
+ for (std::vector<ImplFilter>::const_iterator i = filters.begin(); i != filters.end(); ++i)
+ delete i->regex;
+
+ filters.clear();
+}
+
ModResult ModuleFilter::OnUserPreMessage(User* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
{
if (!IS_LOCAL(user))
@@ -457,20 +476,35 @@ void ModuleFilter::OnRehash(User* user)
if (!chan.empty())
exemptfromfilter.insert(chan);
}
- std::string newrxengine = "regex/" + ServerInstance->Config->ConfValue("filteropts")->getString("engine");
- if (newrxengine == "regex/")
- newrxengine = "regex";
- if (RegexEngine.GetProvider() == newrxengine)
- return;
- //ServerInstance->SNO->WriteGlobalSno('a', "Dumping all filters due to regex engine change (was '%s', now '%s')", RegexEngine.GetProvider().c_str(), newrxengine.c_str());
- //ServerInstance->XLines->DelAll("R");
+ std::string newrxengine = ServerInstance->Config->ConfValue("filteropts")->getString("engine");
+
+ factory = RegexEngine ? (RegexEngine.operator->()) : NULL;
+
+ if (newrxengine.empty())
+ RegexEngine.SetProvider("regex");
+ else
+ RegexEngine.SetProvider("regex/" + newrxengine);
- RegexEngine.SetProvider(newrxengine);
if (!RegexEngine)
{
- ServerInstance->SNO->WriteGlobalSno('a', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str());
+ if (newrxengine.empty())
+ ServerInstance->SNO->WriteGlobalSno('a', "WARNING: No regex engine loaded - Filter functionality disabled until this is corrected.");
+ else
+ ServerInstance->SNO->WriteGlobalSno('a', "WARNING: Regex engine '%s' is not loaded - Filter functionality disabled until this is corrected.", newrxengine.c_str());
+
+ initing = false;
+ FreeFilters();
+ return;
+ }
+
+ if ((!initing) && (RegexEngine.operator->() != factory))
+ {
+ ServerInstance->SNO->WriteGlobalSno('a', "Dumping all filters due to regex engine change");
+ FreeFilters();
}
+
+ initing = false;
ReadFilters();
}
@@ -697,4 +731,18 @@ ModResult ModuleFilter::OnStats(char symbol, User* user, string_list &results)
return MOD_RES_PASSTHRU;
}
+void ModuleFilter::OnUnloadModule(Module* mod)
+{
+ // If the regex engine became unavailable or has changed, remove all filters
+ if (!RegexEngine)
+ {
+ FreeFilters();
+ }
+ else if (RegexEngine.operator->() != factory)
+ {
+ factory = RegexEngine.operator->();
+ FreeFilters();
+ }
+}
+
MODULE_INIT(ModuleFilter)
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index f38ad2241..2b5a512c9 100644
--- a/src/modules/m_ident.cpp
+++ b/src/modules/m_ident.cpp
@@ -367,6 +367,7 @@ class ModuleIdent : public Module
user->WriteServ("NOTICE Auth :*** Found your ident, '%s'", user->ident.c_str());
}
+ user->InvalidateCache();
isock->Close();
ext.unset(user);
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp
index 5f19e5d0c..2f0c15bf3 100644
--- a/src/modules/m_kicknorejoin.cpp
+++ b/src/modules/m_kicknorejoin.cpp
@@ -27,31 +27,46 @@
/* $ModDesc: Provides channel mode +J (delay rejoin after kick) */
-typedef std::map<User*, time_t> delaylist;
+typedef std::map<std::string, time_t> delaylist;
/** Handles channel mode +J
*/
-class KickRejoin : public ParamChannelModeHandler
+class KickRejoin : public ModeHandler
{
+ static const unsigned int max = 60;
public:
SimpleExtItem<delaylist> ext;
- KickRejoin(Module* Creator) : ParamChannelModeHandler(Creator, "kicknorejoin", 'J'), ext("norejoinusers", Creator) { }
-
- bool ParamValidate(std::string& parameter)
+ KickRejoin(Module* Creator)
+ : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL)
+ , ext("norejoinusers", Creator)
{
- int v = atoi(parameter.c_str());
- if (v <= 0)
- return false;
- parameter = ConvToStr(v);
- return true;
}
- ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
+ ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding)
{
- ModeAction rv = ParamChannelModeHandler::OnModeChange(source, dest, channel, parameter, adding);
- if (rv == MODEACTION_ALLOW && !adding)
+ if (adding)
+ {
+ int v = ConvToInt(parameter);
+ if (v <= 0)
+ return MODEACTION_DENY;
+ if (parameter == channel->GetModeParameter(this))
+ return MODEACTION_DENY;
+
+ if ((IS_LOCAL(source) && ((unsigned int)v > max)))
+ v = max;
+
+ parameter = ConvToStr(v);
+ channel->SetModeParam(this, parameter);
+ }
+ else
+ {
+ if (!channel->IsModeSet(this))
+ return MODEACTION_DENY;
+
ext.unset(channel);
- return rv;
+ channel->SetModeParam(this, "");
+ }
+ return MODEACTION_ALLOW;
}
};
@@ -80,30 +95,26 @@ public:
delaylist* dl = kr.ext.get(chan);
if (dl)
{
- std::vector<User*> itemstoremove;
-
- for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++)
+ for (delaylist::iterator iter = dl->begin(); iter != dl->end(); )
{
if (iter->second > ServerInstance->Time())
{
- if (iter->first == user)
+ if (iter->first == user->uuid)
{
std::string modeparam = chan->GetModeParameter(&kr);
user->WriteNumeric(ERR_DELAYREJOIN, "%s %s :You must wait %s seconds after being kicked to rejoin (+J)",
user->nick.c_str(), chan->name.c_str(), modeparam.c_str());
return MOD_RES_DENY;
}
+ ++iter;
}
else
{
// Expired record, remove.
- itemstoremove.push_back(iter->first);
+ dl->erase(iter++);
}
}
- for (unsigned int i = 0; i < itemstoremove.size(); i++)
- dl->erase(itemstoremove[i]);
-
if (!dl->size())
kr.ext.unset(chan);
}
@@ -113,7 +124,7 @@ public:
void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts)
{
- if (memb->chan->IsModeSet(&kr) && (source != memb->user))
+ if (memb->chan->IsModeSet(&kr) && (IS_LOCAL(memb->user)) && (source != memb->user))
{
delaylist* dl = kr.ext.get(memb->chan);
if (!dl)
@@ -121,7 +132,7 @@ public:
dl = new delaylist;
kr.ext.set(memb->chan, dl);
}
- (*dl)[memb->user] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr));
+ (*dl)[memb->user->uuid] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr));
}
}
diff --git a/src/modules/m_nonotice.cpp b/src/modules/m_nonotice.cpp
index 89e6be3b7..3a2f0814f 100644
--- a/src/modules/m_nonotice.cpp
+++ b/src/modules/m_nonotice.cpp
@@ -59,11 +59,6 @@ class ModuleNoNotice : public Module
Channel* c = (Channel*)dest;
if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet('T')))
{
- if (ServerInstance->ULine(user->server))
- {
- // ulines are exempt.
- return MOD_RES_PASSTHRU;
- }
res = ServerInstance->OnCheckExemption(user,c,"nonotice");
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp
index 27026bde9..6a8694a1c 100644
--- a/src/modules/m_permchannels.cpp
+++ b/src/modules/m_permchannels.cpp
@@ -172,14 +172,6 @@ public:
ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
OnRehash(NULL);
-
- // Load only when there are no linked servers - we set the TS of the channels we
- // create to the current time, this can lead to desync because spanningtree has
- // no way of knowing what we do
- ProtoServerList serverlist;
- ServerInstance->PI->GetServerList(serverlist);
- if (serverlist.size() < 2)
- LoadDatabase();
}
CullResult cull()
@@ -300,6 +292,38 @@ public:
dirty = false;
}
+ void Prioritize()
+ {
+ // XXX: Load the DB here because the order in which modules are init()ed at boot is
+ // alphabetical, this means we must wait until all modules have done their init()
+ // to be able to set the modes they provide (e.g.: m_stripcolor is inited after us)
+ // Prioritize() is called after all module initialization is complete, consequently
+ // all modes are available now
+
+ static bool loaded = false;
+ if (loaded)
+ return;
+
+ loaded = true;
+
+ // Load only when there are no linked servers - we set the TS of the channels we
+ // create to the current time, this can lead to desync because spanningtree has
+ // no way of knowing what we do
+ ProtoServerList serverlist;
+ ServerInstance->PI->GetServerList(serverlist);
+ if (serverlist.size() < 2)
+ {
+ try
+ {
+ LoadDatabase();
+ }
+ catch (CoreException& e)
+ {
+ ServerInstance->Logs->Log("m_permchannels", LOG_DEFAULT, "Error loading permchannels database: " + std::string(e.GetReason()));
+ }
+ }
+ }
+
virtual Version GetVersion()
{
return Version("Provides support for channel mode +P to provide permanent channels",VF_VENDOR);
diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp
index c4439cbfb..d164f5fef 100644
--- a/src/modules/m_rline.cpp
+++ b/src/modules/m_rline.cpp
@@ -214,9 +214,13 @@ class ModuleRLine : public Module
RLineFactory f;
CommandRLine r;
bool MatchOnNickChange;
+ bool initing;
+ RegexFactory* factory;
public:
- ModuleRLine() : rxfactory(this, "regex"), f(rxfactory), r(this, f)
+ ModuleRLine()
+ : rxfactory(this, "regex"), f(rxfactory), r(this, f)
+ , initing(true)
{
}
@@ -227,7 +231,7 @@ class ModuleRLine : public Module
ServerInstance->Modules->AddService(r);
ServerInstance->XLines->RegisterFactory(&f);
- Implementation eventlist[] = { I_OnUserConnect, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer };
+ Implementation eventlist[] = { I_OnUserRegister, I_OnRehash, I_OnUserPostNick, I_OnStats, I_OnBackgroundTimer, I_OnUnloadModule };
ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
}
@@ -242,7 +246,7 @@ class ModuleRLine : public Module
return Version("RLINE: Regexp user banning.", VF_COMMON | VF_VENDOR, rxfactory ? rxfactory->name : "");
}
- virtual void OnUserConnect(LocalUser* user)
+ ModResult OnUserRegister(LocalUser* user)
{
// Apply lines on user connect
XLine *rl = ServerInstance->XLines->MatchesLine("R", user);
@@ -251,7 +255,9 @@ class ModuleRLine : public Module
{
// Bang. :P
rl->Apply(user);
+ return MOD_RES_DENY;
}
+ return MOD_RES_PASSTHRU;
}
virtual void OnRehash(User *user)
@@ -262,14 +268,29 @@ class ModuleRLine : public Module
ZlineOnMatch = tag->getBool("zlineonmatch");
std::string newrxengine = tag->getString("engine");
+ factory = rxfactory ? (rxfactory.operator->()) : NULL;
+
if (newrxengine.empty())
rxfactory.SetProvider("regex");
else
rxfactory.SetProvider("regex/" + newrxengine);
+
if (!rxfactory)
{
- ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Regex engine '%s' is not loaded - R-Line functionality disabled until this is corrected.", newrxengine.c_str());
+ if (newrxengine.empty())
+ ServerInstance->SNO->WriteToSnoMask('a', "WARNING: No regex engine loaded - R-Line functionality disabled until this is corrected.");
+ else
+ ServerInstance->SNO->WriteToSnoMask('a', "WARNING: Regex engine '%s' is not loaded - R-Line functionality disabled until this is corrected.", newrxengine.c_str());
+
+ ServerInstance->XLines->DelAll(f.GetType());
}
+ else if ((!initing) && (rxfactory.operator->() != factory))
+ {
+ ServerInstance->SNO->WriteToSnoMask('a', "Regex engine has changed, removing all R-Lines");
+ ServerInstance->XLines->DelAll(f.GetType());
+ }
+
+ initing = false;
}
virtual ModResult OnStats(char symbol, User* user, string_list &results)
@@ -307,6 +328,25 @@ class ModuleRLine : public Module
}
}
+ void OnUnloadModule(Module* mod)
+ {
+ // If the regex engine became unavailable or has changed, remove all rlines
+ if (!rxfactory)
+ {
+ ServerInstance->XLines->DelAll(f.GetType());
+ }
+ else if (rxfactory.operator->() != factory)
+ {
+ factory = rxfactory.operator->();
+ ServerInstance->XLines->DelAll(f.GetType());
+ }
+ }
+
+ void Prioritize()
+ {
+ Module* mod = ServerInstance->Modules->Find("m_cgiirc.so");
+ ServerInstance->Modules->SetPriority(this, I_OnUserRegister, PRIORITY_AFTER, mod);
+ }
};
MODULE_INIT(ModuleRLine)
diff --git a/src/modules/m_services_account.cpp b/src/modules/m_services_account.cpp
index 7c4eb5f0b..81ff3e4c3 100644
--- a/src/modules/m_services_account.cpp
+++ b/src/modules/m_services_account.cpp
@@ -37,7 +37,7 @@ class Channel_r : public ModeHandler
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
{
// only a u-lined server may add or remove the +r mode.
- if (!IS_LOCAL(source) || ServerInstance->ULine(source->server))
+ if (!IS_LOCAL(source))
{
// Only change the mode if it's not redundant
if ((adding != channel->IsModeSet('r')))
@@ -64,7 +64,7 @@ class User_r : public ModeHandler
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
{
- if (!IS_LOCAL(source) || ServerInstance->ULine(source->server))
+ if (!IS_LOCAL(source))
{
if ((adding != dest->IsModeSet('r')))
{
@@ -171,12 +171,6 @@ class ModuleServicesAccount : public Module
std::string *account = accountname.get(user);
bool is_registered = account && !account->empty();
- if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
- {
- // user is ulined, can speak regardless
- return MOD_RES_PASSTHRU;
- }
-
if (target_type == TYPE_CHANNEL)
{
Channel* c = (Channel*)dest;
@@ -252,12 +246,6 @@ class ModuleServicesAccount : public Module
if (chan)
{
- if ((ServerInstance->ULine(user->nick.c_str())) || (ServerInstance->ULine(user->server)))
- {
- // user is ulined, won't be stopped from joining
- return MOD_RES_PASSTHRU;
- }
-
if (chan->IsModeSet('R'))
{
if (!is_registered)
diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp
index 018fcece7..1fa7ef76b 100644
--- a/src/modules/m_spanningtree/main.cpp
+++ b/src/modules/m_spanningtree/main.cpp
@@ -731,7 +731,7 @@ void ModuleSpanningTree::OnRehash(User* user)
std::string msg = "Error in configuration: ";
msg.append(e.GetReason());
ServerInstance->SNO->WriteToSnoMask('l', msg);
- if (!IS_LOCAL(user))
+ if (user && !IS_LOCAL(user))
ServerInstance->PI->SendSNONotice("L", msg);
}
}
diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp
index 19e2d53a6..85204ccaa 100644
--- a/src/modules/m_spanningtree/server.cpp
+++ b/src/modules/m_spanningtree/server.cpp
@@ -125,8 +125,9 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist &params)
TreeServer* CheckDupe = Utils->FindServer(sname);
if (CheckDupe)
{
- this->SendError("Server "+sname+" already exists on server "+CheckDupe->GetParent()->GetName()+"!");
- ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+CheckDupe->GetParent()->GetName());
+ std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>";
+ SendError("Server "+sname+" already exists on server "+pname+"!");
+ ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname);
return false;
}
CheckDupe = Utils->FindServer(sid);
@@ -168,6 +169,33 @@ bool TreeSocket::Outbound_Reply_Server(parameterlist &params)
return false;
}
+bool TreeSocket::CheckDuplicate(const std::string& sname, const std::string& sid)
+{
+ /* Check for fully initialized instances of the server by name */
+ TreeServer* CheckDupe = Utils->FindServer(sname);
+ if (CheckDupe)
+ {
+ std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>";
+ SendError("Server "+sname+" already exists on server "+pname+"!");
+ ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname);
+ return false;
+ }
+
+ /* Check for fully initialized instances of the server by id */
+ ServerInstance->Logs->Log("m_spanningtree", LOG_DEBUG, "Looking for dupe SID %s", sid.c_str());
+ CheckDupe = Utils->FindServerID(sid);
+
+ if (CheckDupe)
+ {
+ this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
+ ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+
+ "' already exists on server "+CheckDupe->GetName());
+ return false;
+ }
+
+ return true;
+}
+
/*
* Someone else is attempting to connect to us if this is called. Validate their credentials etc.
* -- w
@@ -206,39 +234,24 @@ bool TreeSocket::Inbound_Server(parameterlist &params)
continue;
}
- /* Now check for fully initialized ServerInstances of the server by name */
- TreeServer* CheckDupe = Utils->FindServer(sname);
- if (CheckDupe)
- {
- std::string pname = CheckDupe->GetParent() ? CheckDupe->GetParent()->GetName() : "<ourself>";
- SendError("Server "+sname+" already exists on server "+pname+"!");
- ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, already exists on server "+pname);
+ if (!CheckDuplicate(sname, sid))
return false;
- }
- /* Check for fully initialized instances of the server by id */
- ServerInstance->Logs->Log("m_spanningtree",LOG_DEBUG,"Looking for dupe SID %s", sid.c_str());
- CheckDupe = Utils->FindServerID(sid);
+ ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection " + linkID + " ("+description+")");
- if (CheckDupe)
- {
- this->SendError("Server ID "+CheckDupe->GetID()+" already exists on server "+CheckDupe->GetName()+"! You may want to specify the server ID for the server manually with <server:id> so they do not conflict.");
- ServerInstance->SNO->WriteToSnoMask('l',"Server connection from \2"+sname+"\2 denied, server ID '"+CheckDupe->GetID()+
- "' already exists on server "+CheckDupe->GetName());
- return false;
- }
+ this->SendCapabilities(2);
- ServerInstance->SNO->WriteToSnoMask('l',"Verified incoming server connection " + linkID + " ("+description+")");
- linkID = sname;
+ // Save these for later, so when they accept our credentials (indicated by BURST) we remember them
+ this->capab->hidden = x->Hidden;
+ this->capab->sid = sid;
+ this->capab->description = description;
+ this->capab->name = sname;
- // this is good. Send our details: Our server name and description and hopcount of 0,
+ // Send our details: Our server name and description and hopcount of 0,
// along with the sendpass from this block.
- this->SendCapabilities(2);
this->WriteLine("SERVER "+ServerInstance->Config->ServerName+" "+this->MakePass(x->SendPass, this->GetTheirChallenge())+" 0 "+ServerInstance->Config->GetSID()+" :"+ServerInstance->Config->ServerDesc);
- // move to the next state, we are now waiting for THEM.
- MyRoot = new TreeServer(Utils, sname, description, sid, Utils->TreeRoot, this, x->Hidden);
- Utils->TreeRoot->AddChild(MyRoot);
+ // move to the next state, we are now waiting for THEM.
this->LinkState = WAIT_AUTH_2;
return true;
}
diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h
index b6230a6a5..0a519041c 100644
--- a/src/modules/m_spanningtree/treesocket.h
+++ b/src/modules/m_spanningtree/treesocket.h
@@ -75,6 +75,12 @@ struct CapabData
int capab_phase; /* Have sent CAPAB already */
bool auth_fingerprint; /* Did we auth using SSL fingerprint */
bool auth_challenge; /* Did we auth using challenge/response */
+
+ // Data saved from incoming SERVER command, for later use when our credentials have been accepted by the other party
+ std::string description;
+ std::string sid;
+ std::string name;
+ bool hidden;
};
/** Every SERVER connection inbound or outbound is represented by an object of
@@ -92,6 +98,11 @@ class TreeSocket : public BufferedSocket
bool LastPingWasGood; /* Responded to last ping we sent? */
int proto_version; /* Remote protocol version */
bool ConnectionFailureShown; /* Set to true if a connection failure message was shown */
+
+ /** Checks if the given servername and sid are both free
+ */
+ bool CheckDuplicate(const std::string& servername, const std::string& sid);
+
public:
time_t age;
diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp
index 1504a8807..fdd28a734 100644
--- a/src/modules/m_spanningtree/treesocket2.cpp
+++ b/src/modules/m_spanningtree/treesocket2.cpp
@@ -160,9 +160,21 @@ void TreeSocket::ProcessLine(std::string &line)
ServerInstance->SNO->WriteGlobalSno('l',"\2WARNING\2: Your clocks are out by %d seconds. Please consider synching your clocks.", abs((long)delta));
}
}
+
+ // Check for duplicate server name/sid again, it's possible that a new
+ // server was introduced while we were waiting for them to send BURST.
+ // (we do not reserve their server name/sid when they send SERVER, we do it now)
+ if (!CheckDuplicate(capab->name, capab->sid))
+ return;
+
this->LinkState = CONNECTED;
Utils->timeoutlist.erase(this);
+ linkID = capab->name;
+
+ MyRoot = new TreeServer(Utils, capab->name, capab->description, capab->sid, Utils->TreeRoot, this, capab->hidden);
+ Utils->TreeRoot->AddChild(MyRoot);
+
MyRoot->bursting = true;
this->DoBurst(MyRoot);
diff --git a/src/socketengine.cpp b/src/socketengine.cpp
index 44f65e1d5..80e9eaed9 100644
--- a/src/socketengine.cpp
+++ b/src/socketengine.cpp
@@ -166,12 +166,7 @@ int SocketEngine::NonBlocking(int fd)
void SocketEngine::SetReuse(int fd)
{
int on = 1;
- struct linger linger = { 0, 0 };
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
- /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
- linger.l_onoff = 1;
- linger.l_linger = 1;
- setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&linger, sizeof(linger));
}
int SocketEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, sockaddr *from, socklen_t *fromlen)
diff --git a/src/usermanager.cpp b/src/usermanager.cpp
index f1a3c0183..78ec673b9 100644
--- a/src/usermanager.cpp
+++ b/src/usermanager.cpp
@@ -63,7 +63,7 @@ void UserManager::AddUser(int socket, ListenSocket* via, irc::sockets::sockaddrs
this->unregistered_count++;
/* The users default nick is their UUID */
- New->nick.assign(New->uuid, 0, ServerInstance->Config->Limits.NickMax);
+ New->nick = New->uuid;
(*(this->clientlist))[New->nick] = New;
New->registered = REG_NONE;
@@ -153,13 +153,13 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char
{
if (user->quitting)
{
- ServerInstance->Logs->Log("CULLLIST",LOG_DEBUG, "*** Warning *** - You tried to quit a user (%s) twice. Did your module call QuitUser twice?", user->nick.c_str());
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit quitting user: " + user->nick);
return;
}
if (IS_SERVER(user))
{
- ServerInstance->Logs->Log("CULLLIST",LOG_DEBUG, "*** Warning *** - You tried to quit a fake user (%s)", user->nick.c_str());
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Tried to quit server user: " + user->nick);
return;
}
@@ -224,7 +224,7 @@ void UserManager::QuitUser(User *user, const std::string &quitreason, const char
if (iter != this->clientlist->end())
this->clientlist->erase(iter);
else
- ServerInstance->Logs->Log("USERS", LOG_DEBUG, "iter == clientlist->end, can't remove them from hash... problematic..");
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Nick not found in clientlist, cannot remove: " + user->nick);
ServerInstance->Users->uuidlist->erase(user->uuid);
}
diff --git a/src/users.cpp b/src/users.cpp
index 623af7fe3..cdc6beed2 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -416,6 +416,7 @@ void UserIOHandler::OnDataReady()
ServerInstance->Users->QuitUser(user, "RecvQ exceeded");
ServerInstance->SNO->WriteToSnoMask('a', "User %s RecvQ of %lu exceeds connect class maximum of %lu",
user->nick.c_str(), (unsigned long)recvq.length(), user->MyClass->GetRecvqMax());
+ return;
}
unsigned long sendqmax = ULONG_MAX;
if (!user->HasPrivPermission("users/flood/increased-buffers"))
@@ -506,6 +507,8 @@ CullResult LocalUser::cull()
// is only a precaution currently.
if (localuseriter != ServerInstance->Users->local_users.end())
ServerInstance->Users->local_users.erase(localuseriter);
+ else
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: LocalUserIter does not point to a valid entry for " + this->nick);
ClearInvites();
eh.cull();
@@ -786,6 +789,12 @@ void User::InvalidateCache()
bool User::ChangeNick(const std::string& newnick, bool force)
{
+ if (quitting)
+ {
+ ServerInstance->Logs->Log("USERS", LOG_DEFAULT, "ERROR: Attempted to change nick of a quitting user: " + this->nick);
+ return false;
+ }
+
ModResult MOD_RESULT;
if (force)