diff options
author | Adam <Adam@anope.org> | 2013-09-29 13:39:59 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2013-09-29 15:41:32 -0400 |
commit | 44dd8d07d9fd3461411c505d8afa6a316184a15c (patch) | |
tree | 9f02aea8964c147bd7e112ba7912ba2ccbd9127a | |
parent | f7aa69b596500413ad33f386e74e28776507ca4f (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.conf | 7 | ||||
-rw-r--r-- | modules/pseudoclients/chanserv.cpp | 35 |
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 ¶m) 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) |