diff options
-rw-r--r-- | data/nickserv.example.conf | 10 | ||||
-rw-r--r-- | docs/Changes.conf | 4 | ||||
-rw-r--r-- | modules/commands/bs_bot.cpp | 22 | ||||
-rw-r--r-- | modules/commands/cs_access.cpp | 10 | ||||
-rw-r--r-- | modules/commands/cs_set.cpp | 10 | ||||
-rw-r--r-- | modules/commands/hs_del.cpp | 3 | ||||
-rw-r--r-- | modules/commands/hs_group.cpp | 2 | ||||
-rw-r--r-- | modules/commands/hs_list.cpp | 2 | ||||
-rw-r--r-- | modules/commands/hs_off.cpp | 5 | ||||
-rw-r--r-- | modules/commands/hs_on.cpp | 3 | ||||
-rw-r--r-- | modules/commands/hs_request.cpp | 1 | ||||
-rw-r--r-- | modules/commands/hs_set.cpp | 3 | ||||
-rw-r--r-- | modules/commands/ns_identify.cpp | 23 | ||||
-rw-r--r-- | modules/commands/ns_register.cpp | 6 | ||||
-rw-r--r-- | modules/m_dns.cpp | 12 | ||||
-rw-r--r-- | modules/protocol/unreal.cpp | 2 | ||||
-rw-r--r-- | modules/pseudoclients/chanserv.cpp | 4 |
17 files changed, 100 insertions, 22 deletions
diff --git a/data/nickserv.example.conf b/data/nickserv.example.conf index e8d02bed6..cda8bc49e 100644 --- a/data/nickserv.example.conf +++ b/data/nickserv.example.conf @@ -381,7 +381,15 @@ command { service = "NickServ"; name = "UNGROUP"; command = "nickserv/ungroup"; * * Used for identifying to accounts. */ -module { name = "ns_identify" } +module +{ + name = "ns_identify" + + /* + * If set, limits the number of concurrent users that can be logged in as a given account at once. + */ + maxlogins = 10 +} command { service = "NickServ"; name = "ID"; command = "nickserv/identify"; hide = true; } command { service = "NickServ"; name = "IDENTIFY"; command = "nickserv/identify"; } diff --git a/docs/Changes.conf b/docs/Changes.conf index 3b90d38e8..5e813b3e4 100644 --- a/docs/Changes.conf +++ b/docs/Changes.conf @@ -1,3 +1,7 @@ +Anope Version 2.0.3-git +------------------- +Add ns_identify:maxlogins to limit the max number of concurrent logins per account + Anope Version 2.0.2 ------------------- Add an operserv/oper/modify privilege, required to use oper add and oper del diff --git a/modules/commands/bs_bot.cpp b/modules/commands/bs_bot.cpp index d066a49a8..6a4f0344a 100644 --- a/modules/commands/bs_bot.cpp +++ b/modules/commands/bs_bot.cpp @@ -75,6 +75,13 @@ class CommandBSBot : public Command return; } + User *u = User::Find(nick, true); + if (u) + { + source.Reply(_("User \2%s\2 is already in use."), u->nick.c_str()); + return; + } + BotInfo *bi = new BotInfo(nick, user, host, real); Log(LOG_ADMIN, source, this) << "ADD " << bi->GetMask() << " " << bi->realname; @@ -161,10 +168,19 @@ class CommandBSBot : public Command return; } - if (!nick.equals_ci(bi->nick) && BotInfo::Find(nick, true)) + if (!nick.equals_ci(bi->nick)) { - source.Reply(_("Bot \002%s\002 already exists."), nick.c_str()); - return; + if (BotInfo::Find(nick, true)) + { + source.Reply(_("Bot \002%s\002 already exists."), nick.c_str()); + return; + } + + if (User::Find(nick, true)) + { + source.Reply(_("User \2%s\2 is already in use."), nick.c_str()); + return; + } } if (!nick.equals_ci(bi->nick)) diff --git a/modules/commands/cs_access.cpp b/modules/commands/cs_access.cpp index 7fef5bfc5..2fc245690 100644 --- a/modules/commands/cs_access.cpp +++ b/modules/commands/cs_access.cpp @@ -758,12 +758,20 @@ class CommandCSLevels : public Command return; } + bool has_access = false; + if (source.HasPriv("chanserv/access/modify")) + has_access = true; + else if (cmd.equals_ci("LIST") && source.HasPriv("chanserv/access/list")) + has_access = true; + else if (source.AccessFor(ci).HasPriv("FOUNDER")) + has_access = true; + /* If SET, we want two extra parameters; if DIS[ABLE] or FOUNDER, we want only * one; else, we want none. */ if (cmd.equals_ci("SET") ? s.empty() : (cmd.substr(0, 3).equals_ci("DIS") ? (what.empty() || !s.empty()) : !what.empty())) this->OnSyntaxError(source, cmd); - else if (!source.AccessFor(ci).HasPriv("FOUNDER") && !source.HasPriv("chanserv/access/modify")) + else if (!has_access) source.Reply(ACCESS_DENIED); else if (Anope::ReadOnly && !cmd.equals_ci("LIST")) source.Reply(READ_ONLY_MODE); diff --git a/modules/commands/cs_set.cpp b/modules/commands/cs_set.cpp index 73bdb5a0c..cfff16377 100644 --- a/modules/commands/cs_set.cpp +++ b/modules/commands/cs_set.cpp @@ -1207,6 +1207,8 @@ class CSSet : public Module CommandCSSetSuccessor commandcssetsuccessor; CommandCSSetNoexpire commandcssetnoexpire; + ExtensibleRef<bool> inhabit; + bool persist_lower_ts; public: @@ -1221,7 +1223,9 @@ class CSSet : public Module commandcssetdescription(this), commandcssetfounder(this), commandcssetkeepmodes(this), commandcssetpeace(this), commandcssetpersist(this), commandcssetrestricted(this), commandcssetsecure(this), commandcssetsecurefounder(this), commandcssetsecureops(this), commandcssetsignkick(this), - commandcssetsuccessor(this), commandcssetnoexpire(this) + commandcssetsuccessor(this), commandcssetnoexpire(this), + + inhabit("inhabit") { } @@ -1271,7 +1275,7 @@ class CSSet : public Module if (mode->name == "PERM") persist.Set(c->ci, true); - if (mode->type != MODE_STATUS && !c->syncing && Me->IsSynced()) + if (mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && (!inhabit || !inhabit->HasExt(c))) c->ci->last_modes = c->GetModes(); } @@ -1286,7 +1290,7 @@ class CSSet : public Module persist.Unset(c->ci); } - if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced()) + if (c->ci && mode->type != MODE_STATUS && !c->syncing && Me->IsSynced() && (!inhabit || !inhabit->HasExt(c))) c->ci->last_modes = c->GetModes(); return EVENT_CONTINUE; diff --git a/modules/commands/hs_del.cpp b/modules/commands/hs_del.cpp index c27dc89d0..e103b8250 100644 --- a/modules/commands/hs_del.cpp +++ b/modules/commands/hs_del.cpp @@ -105,7 +105,8 @@ class HSDel : public Module HSDel(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhsdel(this), commandhsdelall(this) { - + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } }; diff --git a/modules/commands/hs_group.cpp b/modules/commands/hs_group.cpp index a238c3f99..232b2bef3 100644 --- a/modules/commands/hs_group.cpp +++ b/modules/commands/hs_group.cpp @@ -86,6 +86,8 @@ class HSGroup : public Module HSGroup(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhsgroup(this) { + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } void OnSetVhost(NickAlias *na) anope_override diff --git a/modules/commands/hs_list.cpp b/modules/commands/hs_list.cpp index cbdbb25ae..db63c5cd4 100644 --- a/modules/commands/hs_list.cpp +++ b/modules/commands/hs_list.cpp @@ -152,6 +152,8 @@ class HSList : public Module HSList(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhslist(this) { + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } }; diff --git a/modules/commands/hs_off.cpp b/modules/commands/hs_off.cpp index 96d5fccca..603b863c1 100644 --- a/modules/commands/hs_off.cpp +++ b/modules/commands/hs_off.cpp @@ -29,7 +29,9 @@ class CommandHSOff : public Command source.Reply(HOST_NOT_ASSIGNED); else { + u->vhost.clear(); IRCD->SendVhostDel(u); + u->UpdateHost(); Log(LOG_COMMAND, source, this) << "to disable their vhost"; source.Reply(_("Your vhost was removed and the normal cloaking restored.")); } @@ -56,7 +58,8 @@ class HSOff : public Module HSOff(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhsoff(this) { - + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } }; diff --git a/modules/commands/hs_on.cpp b/modules/commands/hs_on.cpp index d6897283a..d59206e27 100644 --- a/modules/commands/hs_on.cpp +++ b/modules/commands/hs_on.cpp @@ -65,7 +65,8 @@ class HSOn : public Module HSOn(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhson(this) { - + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } }; diff --git a/modules/commands/hs_request.cpp b/modules/commands/hs_request.cpp index 616b2e772..313057d25 100644 --- a/modules/commands/hs_request.cpp +++ b/modules/commands/hs_request.cpp @@ -362,7 +362,6 @@ class HSRequest : public Module commandhsrequest(this), commandhsactive(this), commandhsreject(this), commandhswaiting(this), hostrequest(this, "hostrequest"), request_type("HostRequest", HostRequest::Unserialize) { - if (!IRCD || !IRCD->CanSetVHost) throw ModuleException("Your IRCd does not support vhosts"); } diff --git a/modules/commands/hs_set.cpp b/modules/commands/hs_set.cpp index 2940227aa..72e331e88 100644 --- a/modules/commands/hs_set.cpp +++ b/modules/commands/hs_set.cpp @@ -221,7 +221,8 @@ class HSSet : public Module public: HSSet(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR), commandhsset(this), commandhssetall(this) { - + if (!IRCD || !IRCD->CanSetVHost) + throw ModuleException("Your IRCd does not support vhosts"); } }; diff --git a/modules/commands/ns_identify.cpp b/modules/commands/ns_identify.cpp index ce564321c..4aa361a0a 100644 --- a/modules/commands/ns_identify.cpp +++ b/modules/commands/ns_identify.cpp @@ -77,16 +77,27 @@ class CommandNSIdentify : public Command NickAlias *na = NickAlias::Find(nick); if (na && na->nc->HasExt("NS_SUSPENDED")) + { source.Reply(NICK_X_SUSPENDED, na->nick.c_str()); - else if (u->Account() && na && u->Account() == na->nc) + return; + } + + if (u->Account() && na && u->Account() == na->nc) + { source.Reply(_("You are already identified.")); - else + return; + } + + unsigned int maxlogins = Config->GetModule(this->owner)->Get<unsigned int>("maxlogins"); + if (na && maxlogins && na->nc->users.size() >= maxlogins) { - NSIdentifyRequest *req = new NSIdentifyRequest(owner, source, this, na ? na->nc->display : nick, pass); - FOREACH_MOD(OnCheckAuthentication, (u, req)); - req->Dispatch(); + source.Reply(_("Account \2%s\2 has exceeeded the maximum number of simultaneous logins (%u)."), na->nc->display.c_str(), maxlogins); + return; } - return; + + NSIdentifyRequest *req = new NSIdentifyRequest(owner, source, this, na ? na->nc->display : nick, pass); + FOREACH_MOD(OnCheckAuthentication, (u, req)); + req->Dispatch(); } bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override diff --git a/modules/commands/ns_register.cpp b/modules/commands/ns_register.cpp index 75ef5a9fb..5fe70437a 100644 --- a/modules/commands/ns_register.cpp +++ b/modules/commands/ns_register.cpp @@ -158,6 +158,12 @@ class CommandNSRegister : public Command return; } + if (BotInfo::Find(u_nick, true)) + { + source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str()); + return; + } + if (Config->GetModule("nickserv")->Get<bool>("restrictopernicks")) for (unsigned i = 0; i < Oper::opers.size(); ++i) { diff --git a/modules/m_dns.cpp b/modules/m_dns.cpp index 8a2ed5fee..dfa2cc969 100644 --- a/modules/m_dns.cpp +++ b/modules/m_dns.cpp @@ -26,6 +26,11 @@ namespace */ class Packet : public Query { + static bool IsValidName(const Anope::string &name) + { + return name.find_first_not_of("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-") == Anope::string::npos; + } + void PackName(unsigned char *output, unsigned short output_size, unsigned short &pos, const Anope::string &name) { if (pos + name.length() + 2 > output_size) @@ -116,6 +121,9 @@ class Packet : public Query if (pos + 4 > input_size) throw SocketException("Unable to unpack question"); + if (!IsValidName(question.name)) + throw SocketException("Invalid question name"); + question.type = static_cast<QueryType>(input[pos] << 8 | input[pos + 1]); pos += 2; @@ -179,6 +187,10 @@ class Packet : public Query case QUERY_PTR: { record.rdata = this->UnpackName(input, input_size, pos); + + if (!IsValidName(record.rdata)) + throw SocketException("Invalid cname/ptr record data"); + break; } default: diff --git a/modules/protocol/unreal.cpp b/modules/protocol/unreal.cpp index 1bb0db657..ef8393b74 100644 --- a/modules/protocol/unreal.cpp +++ b/modules/protocol/unreal.cpp @@ -1220,7 +1220,7 @@ class ProtoUnreal : public Module ModeManager::AddUserMode(new UserModeOperOnly("CO_ADMIN", 'C')); ModeManager::AddUserMode(new UserMode("CENSOR", 'G')); ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H')); - ModeManager::AddUserMode(new UserMode("HIDEIDLE", 'I')); + ModeManager::AddUserMode(new UserModeOperOnly("HIDEIDLE", 'I')); ModeManager::AddUserMode(new UserModeOperOnly("NETADMIN", 'N')); ModeManager::AddUserMode(new UserMode("REGPRIV", 'R')); ModeManager::AddUserMode(new UserModeOperOnly("PROTECTED", 'S')); diff --git a/modules/pseudoclients/chanserv.cpp b/modules/pseudoclients/chanserv.cpp index 41a62d7b4..0ceeded25 100644 --- a/modules/pseudoclients/chanserv.cpp +++ b/modules/pseudoclients/chanserv.cpp @@ -66,12 +66,12 @@ class ChanServCore : public Module, public ChanServService if (!c) return; - inhabit.Unset(c); - /* In the event we don't part */ c->RemoveMode(NULL, "SECRET"); c->RemoveMode(NULL, "INVITE"); + inhabit.Unset(c); /* now we're done changing modes, unset inhabit */ + if (!c->ci || !c->ci->bi) { if (ChanServ) |