summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/nickserv.example.conf10
-rw-r--r--docs/Changes.conf4
-rw-r--r--modules/commands/bs_bot.cpp22
-rw-r--r--modules/commands/cs_access.cpp10
-rw-r--r--modules/commands/cs_set.cpp10
-rw-r--r--modules/commands/hs_del.cpp3
-rw-r--r--modules/commands/hs_group.cpp2
-rw-r--r--modules/commands/hs_list.cpp2
-rw-r--r--modules/commands/hs_off.cpp5
-rw-r--r--modules/commands/hs_on.cpp3
-rw-r--r--modules/commands/hs_request.cpp1
-rw-r--r--modules/commands/hs_set.cpp3
-rw-r--r--modules/commands/ns_identify.cpp23
-rw-r--r--modules/commands/ns_register.cpp6
-rw-r--r--modules/m_dns.cpp12
-rw-r--r--modules/protocol/unreal.cpp2
-rw-r--r--modules/pseudoclients/chanserv.cpp4
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)