summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2013-09-29 13:39:59 -0400
committerAdam <Adam@anope.org>2013-09-29 15:41:32 -0400
commit44dd8d07d9fd3461411c505d8afa6a316184a15c (patch)
tree9f02aea8964c147bd7e112ba7912ba2ccbd9127a
parentf7aa69b596500413ad33f386e74e28776507ca4f (diff)
Add chanserv:always_lower_ts config option to always lower registered
channels timestamps to the creation time which fixes some race conditions regarding users joining empty registered channels and doing things prior to the -o from services coming through. Without always_lower_ts attempt to bounce mode changes from bad users, which will work okay in most cases.
-rw-r--r--data/chanserv.example.conf7
-rw-r--r--modules/pseudoclients/chanserv.cpp35
2 files changed, 41 insertions, 1 deletions
diff --git a/data/chanserv.example.conf b/data/chanserv.example.conf
index 5f7324503..7ec4487bf 100644
--- a/data/chanserv.example.conf
+++ b/data/chanserv.example.conf
@@ -159,6 +159,13 @@ module
* If set, prevents channels from being on access lists.
*/
disallow_channel_access = false
+
+ /*
+ * If set, ChanServ will always lower the timestamp of registered channels to their registration date.
+ * This prevents several race conditions where unauthorized users can join empty registered channels and set
+ * modes etc. prior to services deopping them.
+ */
+ always_lower_ts = false
}
/*
diff --git a/modules/pseudoclients/chanserv.cpp b/modules/pseudoclients/chanserv.cpp
index f3045c256..9a3e309a7 100644
--- a/modules/pseudoclients/chanserv.cpp
+++ b/modules/pseudoclients/chanserv.cpp
@@ -18,10 +18,11 @@ class ChanServCore : public Module, public ChanServService
std::vector<Anope::string> defaults;
ExtensibleItem<bool> inhabit;
ExtensibleRef<bool> persist;
+ bool always_lower;
public:
ChanServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR),
- ChanServService(this), inhabit(this, "inhabit"), persist("PERSIST")
+ ChanServService(this), inhabit(this, "inhabit"), persist("PERSIST"), always_lower(false)
{
}
@@ -106,6 +107,8 @@ class ChanServCore : public Module, public ChanServService
}
else if (defaults[0].equals_ci("none"))
defaults.clear();
+
+ always_lower = conf->GetModule(this)->Get<bool>("always_lower_ts");
}
void OnBotDelete(BotInfo *bi) anope_override
@@ -421,6 +424,36 @@ class ChanServCore : public Module, public ChanServService
else if (persist->Get(ci))
ci->c->SetMode(NULL, "PERM");
}
+
+ void OnJoinChannel(User *u, Channel *c) anope_override
+ {
+ if (always_lower && c->ci && c->creation_time > c->ci->time_registered)
+ {
+ Log(LOG_DEBUG) << "Changing TS of " << c->name << " from " << c->creation_time << " to " << c->ci->time_registered;
+ c->creation_time = c->ci->time_registered;
+ IRCD->SendChannel(c);
+ c->Reset();
+ }
+ }
+
+ EventReturn OnChannelModeSet(Channel *c, MessageSource &setter, ChannelMode *mode, const Anope::string &param) anope_override
+ {
+ if (!always_lower && Anope::CurTime == c->creation_time && c->ci && setter.GetUser())
+ {
+ ChanUserContainer *cu = c->FindUser(setter.GetUser());
+ ChannelMode *cm = ModeManager::FindChannelModeByName("OP");
+ if (cu && cm && !cu->status.HasMode(cm->mchar))
+ {
+ /* Our -o and their mode change crossing, bounce their mode */
+ c->RemoveMode(c->ci->WhoSends(), mode, param);
+ /* We don't set mlocks until after the join has finished processing, it will stack with this change,
+ * so there isn't much for the user to remove except -nt etc which is likely locked anyway.
+ */
+ }
+ }
+
+ return EVENT_CONTINUE;
+ }
};
MODULE_INIT(ChanServCore)