anope/src/access.cpp

476 lines
11 KiB
C++

/*
*
* (C) 2003-2022 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "service.h"
#include "access.h"
#include "regchannel.h"
#include "users.h"
#include "account.h"
#include "protocol.h"
static struct
{
Anope::string name;
Anope::string desc;
} descriptions[] = {
{"ACCESS_CHANGE", _("Allowed to modify the access list")},
{"ACCESS_LIST", _("Allowed to view the access list")},
{"AKICK", _("Allowed to use the AKICK command")},
{"ASSIGN", _("Allowed to assign/unassign a bot")},
{"AUTOHALFOP", _("Automatic halfop upon join")},
{"AUTOOP", _("Automatic channel operator status upon join")},
{"AUTOOWNER", _("Automatic owner upon join")},
{"AUTOPROTECT", _("Automatic protect upon join")},
{"AUTOVOICE", _("Automatic voice on join")},
{"BADWORDS", _("Allowed to modify channel badwords list")},
{"BAN", _("Allowed to ban users")},
{"FANTASIA", _("Allowed to use fantasy commands")},
{"FOUNDER", _("Allowed to issue commands restricted to channel founders")},
{"GETKEY", _("Allowed to use GETKEY command")},
{"GREET", _("Greet message displayed on join")},
{"HALFOP", _("Allowed to (de)halfop users")},
{"HALFOPME", _("Allowed to (de)halfop him/herself")},
{"INFO", _("Allowed to get full INFO output")},
{"INVITE", _("Allowed to use the INVITE command")},
{"KICK", _("Allowed to use the KICK command")},
{"MEMO", _("Allowed to read channel memos")},
{"MODE", _("Allowed to use the MODE command")},
{"NOKICK", _("Prevents users being kicked by Services")},
{"OP", _("Allowed to (de)op users")},
{"OPME", _("Allowed to (de)op him/herself")},
{"OWNER", _("Allowed to (de)owner users")},
{"OWNERME", _("Allowed to (de)owner him/herself")},
{"PROTECT", _("Allowed to (de)protect users")},
{"PROTECTME", _("Allowed to (de)protect him/herself")},
{"SAY", _("Allowed to use SAY and ACT commands")},
{"SET", _("Allowed to set channel settings")},
{"SIGNKICK", _("No signed kick when SIGNKICK LEVEL is used")},
{"TOPIC", _("Allowed to change channel topics")},
{"UNBAN", _("Allowed to unban users")},
{"VOICE", _("Allowed to (de)voice users")},
{"VOICEME", _("Allowed to (de)voice him/herself")}
};
Privilege::Privilege(const Anope::string &n, const Anope::string &d, int r) : name(n), desc(d), rank(r)
{
if (this->desc.empty())
for (unsigned j = 0; j < sizeof(descriptions) / sizeof(*descriptions); ++j)
if (descriptions[j].name.equals_ci(name))
this->desc = descriptions[j].desc;
}
bool Privilege::operator==(const Privilege &other) const
{
return this->name.equals_ci(other.name);
}
std::vector<Privilege> PrivilegeManager::Privileges;
void PrivilegeManager::AddPrivilege(Privilege p)
{
unsigned i;
for (i = 0; i < Privileges.size(); ++i)
{
Privilege &priv = Privileges[i];
if (priv.rank > p.rank)
break;
}
Privileges.insert(Privileges.begin() + i, p);
}
void PrivilegeManager::RemovePrivilege(Privilege &p)
{
std::vector<Privilege>::iterator it = std::find(Privileges.begin(), Privileges.end(), p);
if (it != Privileges.end())
Privileges.erase(it);
for (registered_channel_map::const_iterator cit = RegisteredChannelList->begin(), cit_end = RegisteredChannelList->end(); cit != cit_end; ++cit)
{
cit->second->QueueUpdate();
cit->second->RemoveLevel(p.name);
}
}
Privilege *PrivilegeManager::FindPrivilege(const Anope::string &name)
{
for (unsigned i = Privileges.size(); i > 0; --i)
if (Privileges[i - 1].name.equals_ci(name))
return &Privileges[i - 1];
return NULL;
}
std::vector<Privilege> &PrivilegeManager::GetPrivileges()
{
return Privileges;
}
void PrivilegeManager::ClearPrivileges()
{
Privileges.clear();
}
AccessProvider::AccessProvider(Module *o, const Anope::string &n) : Service(o, "AccessProvider", n)
{
Providers.push_back(this);
}
AccessProvider::~AccessProvider()
{
std::list<AccessProvider *>::iterator it = std::find(Providers.begin(), Providers.end(), this);
if (it != Providers.end())
Providers.erase(it);
}
std::list<AccessProvider *> AccessProvider::Providers;
const std::list<AccessProvider *>& AccessProvider::GetProviders()
{
return Providers;
}
ChanAccess::ChanAccess(AccessProvider *p) : Serializable("ChanAccess"), provider(p)
{
}
ChanAccess::~ChanAccess()
{
if (this->ci)
{
std::vector<ChanAccess *>::iterator it = std::find(this->ci->access->begin(), this->ci->access->end(), this);
if (it != this->ci->access->end())
this->ci->access->erase(it);
if (*nc != NULL)
nc->RemoveChannelReference(this->ci);
else
{
ChannelInfo *c = ChannelInfo::Find(this->mask);
if (c)
c->RemoveChannelReference(this->ci->name);
}
}
}
void ChanAccess::SetMask(const Anope::string &m, ChannelInfo *c)
{
if (*nc != NULL)
nc->RemoveChannelReference(this->ci);
else if (!this->mask.empty())
{
ChannelInfo *targc = ChannelInfo::Find(this->mask);
if (targc)
targc->RemoveChannelReference(this->ci->name);
}
ci = c;
mask.clear();
nc = NULL;
const NickAlias *na = NickAlias::Find(m);
if (na != NULL)
{
nc = na->nc;
nc->AddChannelReference(ci);
}
else
{
mask = m;
ChannelInfo *targci = ChannelInfo::Find(mask);
if (targci != NULL)
targci->AddChannelReference(ci->name);
}
}
const Anope::string &ChanAccess::Mask() const
{
if (nc)
return nc->display;
else
return mask;
}
NickCore *ChanAccess::GetAccount() const
{
return nc;
}
void ChanAccess::Serialize(Serialize::Data &data) const
{
data["provider"] << this->provider->name;
data["ci"] << this->ci->name;
data["mask"] << this->Mask();
data["creator"] << this->creator;
data.SetType("last_seen", Serialize::Data::DT_INT); data["last_seen"] << this->last_seen;
data.SetType("created", Serialize::Data::DT_INT); data["created"] << this->created;
data["data"] << this->AccessSerialize();
}
Serializable* ChanAccess::Unserialize(Serializable *obj, Serialize::Data &data)
{
Anope::string provider, chan;
data["provider"] >> provider;
data["ci"] >> chan;
ServiceReference<AccessProvider> aprovider("AccessProvider", provider);
ChannelInfo *ci = ChannelInfo::Find(chan);
if (!aprovider || !ci)
return NULL;
ChanAccess *access;
if (obj)
access = anope_dynamic_static_cast<ChanAccess *>(obj);
else
access = aprovider->Create();
access->ci = ci;
Anope::string m;
data["mask"] >> m;
access->SetMask(m, ci);
data["creator"] >> access->creator;
data["last_seen"] >> access->last_seen;
data["created"] >> access->created;
Anope::string adata;
data["data"] >> adata;
access->AccessUnserialize(adata);
if (!obj)
ci->AddAccess(access);
return access;
}
bool ChanAccess::Matches(const User *u, const NickCore *acc, ChannelInfo* &next) const
{
next = NULL;
if (this->nc)
return this->nc == acc;
if (u)
{
bool is_mask = this->mask.find_first_of("!@?*") != Anope::string::npos;
if (is_mask && Anope::Match(u->nick, this->mask))
return true;
else if (Anope::Match(u->GetDisplayedMask(), this->mask))
return true;
}
if (acc)
{
for (unsigned i = 0; i < acc->aliases->size(); ++i)
{
const NickAlias *na = acc->aliases->at(i);
if (Anope::Match(na->nick, this->mask))
return true;
}
}
if (IRCD->IsChannelValid(this->mask))
{
next = ChannelInfo::Find(this->mask);
}
return false;
}
bool ChanAccess::operator>(const ChanAccess &other) const
{
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
for (unsigned i = privs.size(); i > 0; --i)
{
bool this_p = this->HasPriv(privs[i - 1].name),
other_p = other.HasPriv(privs[i - 1].name);
if (!this_p && !other_p)
continue;
return this_p && !other_p;
}
return false;
}
bool ChanAccess::operator<(const ChanAccess &other) const
{
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
for (unsigned i = privs.size(); i > 0; --i)
{
bool this_p = this->HasPriv(privs[i - 1].name),
other_p = other.HasPriv(privs[i - 1].name);
if (!this_p && !other_p)
continue;
return !this_p && other_p;
}
return false;
}
bool ChanAccess::operator>=(const ChanAccess &other) const
{
return !(*this < other);
}
bool ChanAccess::operator<=(const ChanAccess &other) const
{
return !(*this > other);
}
AccessGroup::AccessGroup()
{
this->ci = NULL;
this->nc = NULL;
this->super_admin = this->founder = false;
}
static bool HasPriv(const ChanAccess::Path &path, const Anope::string &name)
{
if (path.empty())
return false;
for (unsigned int i = 0; i < path.size(); ++i)
{
ChanAccess *access = path[i];
EventReturn MOD_RESULT;
FOREACH_RESULT(OnCheckPriv, MOD_RESULT, (access, name));
if (MOD_RESULT != EVENT_ALLOW && !access->HasPriv(name))
return false;
}
return true;
}
bool AccessGroup::HasPriv(const Anope::string &name) const
{
if (this->super_admin)
return true;
else if (!ci || ci->GetLevel(name) == ACCESS_INVALID)
return false;
/* Privileges prefixed with auto are understood to be given
* automatically. Sometimes founders want to not automatically
* obtain privileges, so we will let them */
bool auto_mode = !name.find("AUTO");
/* Only grant founder privilege if this isn't an auto mode or if they don't match any entries in this group */
if ((!auto_mode || paths.empty()) && this->founder)
return true;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnGroupCheckPriv, MOD_RESULT, (this, name));
if (MOD_RESULT != EVENT_CONTINUE)
return MOD_RESULT == EVENT_ALLOW;
for (unsigned int i = paths.size(); i > 0; --i)
{
const ChanAccess::Path &path = paths[i - 1];
if (::HasPriv(path, name))
return true;
}
return false;
}
static ChanAccess *HighestInPath(const ChanAccess::Path &path)
{
ChanAccess *highest = NULL;
for (unsigned int i = 0; i < path.size(); ++i)
if (highest == NULL || *path[i] > *highest)
highest = path[i];
return highest;
}
const ChanAccess *AccessGroup::Highest() const
{
ChanAccess *highest = NULL;
for (unsigned int i = 0; i < paths.size(); ++i)
{
ChanAccess *hip = HighestInPath(paths[i]);
if (highest == NULL || *hip > *highest)
highest = hip;
}
return highest;
}
bool AccessGroup::operator>(const AccessGroup &other) const
{
if (other.super_admin)
return false;
else if (this->super_admin)
return true;
else if (other.founder)
return false;
else if (this->founder)
return true;
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
for (unsigned i = privs.size(); i > 0; --i)
{
bool this_p = this->HasPriv(privs[i - 1].name),
other_p = other.HasPriv(privs[i - 1].name);
if (!this_p && !other_p)
continue;
return this_p && !other_p;
}
return false;
}
bool AccessGroup::operator<(const AccessGroup &other) const
{
if (this->super_admin)
return false;
else if (other.super_admin)
return true;
else if (this->founder)
return false;
else if (other.founder)
return true;
const std::vector<Privilege> &privs = PrivilegeManager::GetPrivileges();
for (unsigned i = privs.size(); i > 0; --i)
{
bool this_p = this->HasPriv(privs[i - 1].name),
other_p = other.HasPriv(privs[i - 1].name);
if (!this_p && !other_p)
continue;
return !this_p && other_p;
}
return false;
}
bool AccessGroup::operator>=(const AccessGroup &other) const
{
return !(*this < other);
}
bool AccessGroup::operator<=(const AccessGroup &other) const
{
return !(*this > other);
}