aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Sadie Powell2022-11-27 07:32:42 +0000
committerGravatar Sadie Powell2022-11-28 02:57:50 +0000
commitee44af8d04f23b4a16c9b377764f930d69e575f7 (patch)
tree4348a9d4b76ea65266875651d57d2ebf3e1d7894 /src
parentMerge branch 'insp3' into master. (diff)
Refactor the internals of the oper system.
- Allow overriding privileges from the <class> blocks in the <type> and <oper> blocks. - Separate oper types from oper accounts in the code. This enables moving some core stuff out of the config tag later. - Merge the config tags together to make a synthetic tag that can have getXXX called on it instead of using getConfig and then converting it. - Move the details of Have*Permission into the oper type class. - Improve oper events to allow modules to easily hook into the oper system.
Diffstat (limited to 'src')
-rw-r--r--src/channels.cpp7
-rw-r--r--src/command_parse.cpp2
-rw-r--r--src/configparser.cpp15
-rw-r--r--src/configreader.cpp66
-rw-r--r--src/coremods/core_info/cmd_servlist.cpp4
-rw-r--r--src/coremods/core_oper/cmd_oper.cpp10
-rw-r--r--src/coremods/core_oper/core_oper.cpp15
-rw-r--r--src/coremods/core_oper/core_oper.h7
-rw-r--r--src/coremods/core_oper/umode_o.cpp2
-rw-r--r--src/coremods/core_oper/umode_s.cpp2
-rw-r--r--src/coremods/core_stats.cpp13
-rw-r--r--src/coremods/core_whois.cpp2
-rw-r--r--src/mode.cpp2
-rw-r--r--src/modules.cpp8
-rw-r--r--src/modules/m_check.cpp21
-rw-r--r--src/modules/m_httpd_stats.cpp2
-rw-r--r--src/modules/m_ldapoper.cpp16
-rw-r--r--src/modules/m_operchans.cpp2
-rw-r--r--src/modules/m_operjoin.cpp4
-rw-r--r--src/modules/m_operlevels.cpp4
-rw-r--r--src/modules/m_opermodes.cpp4
-rw-r--r--src/modules/m_opermotd.cpp2
-rw-r--r--src/modules/m_operprefix.cpp4
-rw-r--r--src/modules/m_override.cpp4
-rw-r--r--src/modules/m_spanningtree/commands.h2
-rw-r--r--src/modules/m_spanningtree/main.cpp6
-rw-r--r--src/modules/m_spanningtree/main.h2
-rw-r--r--src/modules/m_spanningtree/netburst.cpp2
-rw-r--r--src/modules/m_spanningtree/opertype.cpp24
-rw-r--r--src/modules/m_sqloper.cpp21
-rw-r--r--src/modules/m_sslinfo.cpp43
-rw-r--r--src/modules/m_swhois.cpp7
-rw-r--r--src/usermanager.cpp2
-rw-r--r--src/users.cpp266
34 files changed, 303 insertions, 290 deletions
diff --git a/src/channels.cpp b/src/channels.cpp
index 591f3368b..d98bcc123 100644
--- a/src/channels.cpp
+++ b/src/channels.cpp
@@ -188,11 +188,8 @@ Channel* Channel::JoinUser(LocalUser* user, std::string cname, bool override, co
{
unsigned long maxchans = user->GetClass()->maxchans;
if (user->IsOper())
- {
- unsigned long opermaxchans = ConvToNum<unsigned int>(user->oper->getConfig("maxchans"));
- if (opermaxchans > maxchans)
- maxchans = opermaxchans;
- }
+ maxchans = user->oper->GetConfig()->getUInt("maxchans", maxchans, maxchans);
+
if (user->chans.size() >= maxchans)
{
user->WriteNumeric(ERR_TOOMANYCHANNELS, cname, "You are on too many channels");
diff --git a/src/command_parse.cpp b/src/command_parse.cpp
index 62b7dcade..950a71c7e 100644
--- a/src/command_parse.cpp
+++ b/src/command_parse.cpp
@@ -281,7 +281,7 @@ void CommandParser::ProcessCommand(LocalUser* user, std::string& command, Comman
{
user->CommandFloodPenalty += failpenalty;
user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to command %s",
- user->oper->name.c_str(), command.c_str()));
+ user->oper->GetType().c_str(), command.c_str()));
FOREACH_MOD(OnCommandBlocked, (command, command_p, user));
return;
}
diff --git a/src/configparser.cpp b/src/configparser.cpp
index 5e892fdfe..04ddd763b 100644
--- a/src/configparser.cpp
+++ b/src/configparser.cpp
@@ -750,18 +750,3 @@ ConfigTag::ConfigTag(const std::string& Name, const FilePosition& Source)
, source(Source)
{
}
-
-OperInfo::OperInfo(const std::string& Name)
- : name(Name)
-{
-}
-
-std::string OperInfo::getConfig(const std::string& key)
-{
- std::string rv;
- if (type_block)
- type_block->readString(key, rv);
- if (oper_block)
- oper_block->readString(key, rv);
- return rv;
-}
diff --git a/src/configreader.cpp b/src/configreader.cpp
index d91f5a389..486bf3ad8 100644
--- a/src/configreader.cpp
+++ b/src/configreader.cpp
@@ -91,61 +91,63 @@ ServerConfig::ServerConfig()
{
}
-typedef std::map<std::string, std::shared_ptr<ConfigTag>> LocalIndex;
-void ServerConfig::CrossCheckOperClassType()
+void ServerConfig::CrossCheckOperBlocks()
{
- LocalIndex operclass;
+ std::unordered_map<std::string, std::shared_ptr<ConfigTag>> operclass;
for (const auto& [_, tag] : ConfTags("class"))
{
- std::string name = tag->getString("name");
+ const std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<class:name> missing from tag at " + tag->source.str());
- if (operclass.find(name) != operclass.end())
+
+ if (!operclass.emplace(name, tag).second)
throw CoreException("Duplicate class block with name " + name + " at " + tag->source.str());
- operclass[name] = tag;
}
for (const auto& [_, tag] : ConfTags("type"))
{
- std::string name = tag->getString("name");
+ const std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<type:name> is missing from tag at " + tag->source.str());
- if (OperTypes.find(name) != OperTypes.end())
- throw CoreException("Duplicate type block with name " + name + " at " + tag->source.str());
- auto ifo = std::make_shared<OperInfo>(name);
- OperTypes[name] = ifo;
- ifo->type_block = tag;
+ auto type = std::make_shared<OperType>(name, nullptr);
- std::string classname;
- irc::spacesepstream str(tag->getString("classes"));
- while (str.GetToken(classname))
+ // Copy the settings from the oper class.
+ irc::spacesepstream classlist(tag->getString("classes"));
+ for (std::string classname; classlist.GetToken(classname); )
{
- LocalIndex::iterator cls = operclass.find(classname);
- if (cls == operclass.end())
- throw CoreException("Oper type " + name + " has missing class " + classname);
- ifo->class_blocks.push_back(cls->second);
+ auto klass = operclass.find(classname);
+ if (klass == operclass.end())
+ throw CoreException("Oper type " + name + " has missing class " + classname + " at " + tag->source.str());
+
+ // Apply the settings from the class.
+ type->Configure(klass->second, false);
}
+
+ // Once the classes have been applied we can apply this.
+ type->Configure(tag, true);
+
+ if (!OperTypes.emplace(name, type).second)
+ throw CoreException("Duplicate type block with name " + name + " at " + tag->source.str());
}
for (const auto& [_, tag] : ConfTags("oper"))
{
- std::string name = tag->getString("name");
+ const std::string name = tag->getString("name");
if (name.empty())
throw CoreException("<oper:name> missing from tag at " + tag->source.str());
- std::string type = tag->getString("type");
- OperIndex::iterator tblk = OperTypes.find(type);
- if (tblk == OperTypes.end())
- throw CoreException("Oper block " + name + " has missing type " + type);
- if (oper_blocks.find(name) != oper_blocks.end())
- throw CoreException("Duplicate oper block with name " + name + " at " + tag->source.str());
+ const std::string typestr = tag->getString("type");
+ if (typestr.empty())
+ throw CoreException("<oper:type> missing from tag at " + tag->source.str());
- auto ifo = std::make_shared<OperInfo>(type);
- ifo->oper_block = tag;
- ifo->type_block = tblk->second->type_block;
- ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end());
- oper_blocks[name] = ifo;
+ auto type = OperTypes.find(typestr);
+ if (type == OperTypes.end())
+ throw CoreException("Oper block " + name + " has missing type " + typestr + " at " + tag->source.str());
+
+ auto account = std::make_shared<OperAccount>(name, type->second, tag);
+ if (!OperAccounts.emplace(name, account).second)
+ throw CoreException("Duplicate oper block with name " + name + " at " + tag->source.str());
}
}
@@ -408,7 +410,7 @@ void ServerConfig::Apply(ServerConfig* old, const std::string& useruid)
Fill();
// Handle special items
- CrossCheckOperClassType();
+ CrossCheckOperBlocks();
CrossCheckConnectBlocks(old);
}
catch (const CoreException& ce)
diff --git a/src/coremods/core_info/cmd_servlist.cpp b/src/coremods/core_info/cmd_servlist.cpp
index 9cb57ed53..40bf6cfdc 100644
--- a/src/coremods/core_info/cmd_servlist.cpp
+++ b/src/coremods/core_info/cmd_servlist.cpp
@@ -44,7 +44,7 @@ CmdResult CommandServList::HandleLocal(LocalUser* user, const Params& parameters
if (serviceuser->IsModeSet(invisiblemode) || !InspIRCd::Match(serviceuser->nick, mask))
continue;
- if (has_type && (!serviceuser->IsOper() || !InspIRCd::Match(serviceuser->oper->name, parameters[2])))
+ if (has_type && (!serviceuser->IsOper() || !InspIRCd::Match(serviceuser->oper->GetType(), parameters[2])))
continue;
Numeric::Numeric numeric(RPL_SERVLIST);
@@ -52,7 +52,7 @@ CmdResult CommandServList::HandleLocal(LocalUser* user, const Params& parameters
.push(serviceuser->nick)
.push(serviceuser->server->GetPublicName())
.push("*")
- .push(serviceuser->IsOper() ? serviceuser->oper->name : "*")
+ .push(serviceuser->IsOper() ? serviceuser->oper->GetType() : "*")
.push(0)
.push(serviceuser->GetRealName());
user->WriteNumeric(numeric);
diff --git a/src/coremods/core_oper/cmd_oper.cpp b/src/coremods/core_oper/cmd_oper.cpp
index 786e047e1..344da7c29 100644
--- a/src/coremods/core_oper/cmd_oper.cpp
+++ b/src/coremods/core_oper/cmd_oper.cpp
@@ -40,18 +40,18 @@ CmdResult CommandOper::HandleLocal(LocalUser* user, const Params& parameters)
bool match_pass = false;
bool match_hosts = false;
- ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
- if (i != ServerInstance->Config->oper_blocks.end())
+ auto i = ServerInstance->Config->OperAccounts.find(parameters[0]);
+ if (i != ServerInstance->Config->OperAccounts.end())
{
- std::shared_ptr<OperInfo> ifo = i->second;
- std::shared_ptr<ConfigTag> tag = ifo->oper_block;
+ std::shared_ptr<OperAccount> ifo = i->second;
+ std::shared_ptr<ConfigTag> tag = ifo->GetConfig();
match_user = true;
match_pass = ServerInstance->PassCompare(user, tag->getString("password"), parameters[1], tag->getString("hash"));
match_hosts = InspIRCd::MatchMask(tag->getString("host"), user->MakeHost(), user->MakeHostIP());
if (match_pass && match_hosts)
{
- user->Oper(ifo);
+ user->OperLogin(ifo);
return CmdResult::SUCCESS;
}
}
diff --git a/src/coremods/core_oper/core_oper.cpp b/src/coremods/core_oper/core_oper.cpp
index ba4e47575..0336b675a 100644
--- a/src/coremods/core_oper/core_oper.cpp
+++ b/src/coremods/core_oper/core_oper.cpp
@@ -54,17 +54,24 @@ public:
cmdkill.hideservicekills = security->getBool("hideservicekills", security->getBool("hideulinekills"));
}
- void OnPostOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
LocalUser* luser = IS_LOCAL(user);
if (!luser)
return;
- const std::string vhost = luser->oper->getConfig("vhost");
+ luser->WriteNumeric(RPL_YOUAREOPER, InspIRCd::Format("You are now %s %s",
+ user->oper->GetType()[0] ? "an" : "a", user->oper->GetType().c_str()));
+
+ ServerInstance->SNO.WriteToSnoMask('o', "%s (%s) is now a server operator of type %s (using account %s)",
+ user->nick.c_str(), user->MakeHost().c_str(), user->oper->GetType().c_str(),
+ user->oper->GetName().c_str());
+
+ const std::string vhost = luser->oper->GetConfig()->getString("vhost");
if (!vhost.empty())
- luser->ChangeDisplayedHost(vhost);
+ user->ChangeDisplayedHost(vhost);
- const std::string klass = luser->oper->getConfig("class");
+ const std::string klass = luser->oper->GetConfig()->getString("class");
if (!klass.empty())
luser->SetClass(klass);
}
diff --git a/src/coremods/core_oper/core_oper.h b/src/coremods/core_oper/core_oper.h
index a6ef6632c..6878b33b5 100644
--- a/src/coremods/core_oper/core_oper.h
+++ b/src/coremods/core_oper/core_oper.h
@@ -23,6 +23,13 @@
#include "inspircd.h"
+enum
+{
+ // From RFC 1459.
+ RPL_YOUAREOPER = 381,
+ ERR_NOOPERHOST = 491,
+};
+
namespace DieRestart
{
/** Send an ERROR to partially connected users and a NOTICE to fully connected users
diff --git a/src/coremods/core_oper/umode_o.cpp b/src/coremods/core_oper/umode_o.cpp
index 0916f51d4..61b6cc56f 100644
--- a/src/coremods/core_oper/umode_o.cpp
+++ b/src/coremods/core_oper/umode_o.cpp
@@ -49,7 +49,7 @@ ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, Mo
*/
char snomask = IS_LOCAL(dest) ? 'o' : 'O';
ServerInstance->SNO.WriteToSnoMask(snomask, "User %s de-opered (by %s)", dest->nick.c_str(), source->nick.c_str());
- dest->UnOper();
+ dest->OperLogout();
return MODEACTION_ALLOW;
}
diff --git a/src/coremods/core_oper/umode_s.cpp b/src/coremods/core_oper/umode_s.cpp
index 1deb459de..70f409113 100644
--- a/src/coremods/core_oper/umode_s.cpp
+++ b/src/coremods/core_oper/umode_s.cpp
@@ -114,7 +114,7 @@ std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::
else if (!user->HasSnomaskPermission(snomask))
{
user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to snomask %c",
- user->oper->name.c_str(), snomask));
+ user->oper->GetType().c_str(), snomask));
continue;
}
}
diff --git a/src/coremods/core_stats.cpp b/src/coremods/core_stats.cpp
index 6d1111f4c..0208dbc8e 100644
--- a/src/coremods/core_stats.cpp
+++ b/src/coremods/core_stats.cpp
@@ -318,10 +318,9 @@ void CommandStats::DoStats(Stats::Context& stats)
/* stats o */
case 'o':
{
- for (const auto& [_, ifo] : ServerInstance->Config->oper_blocks)
+ for (const auto& [_, ifo] : ServerInstance->Config->OperAccounts)
{
- std::shared_ptr<ConfigTag> tag = ifo->oper_block;
- stats.AddRow(243, 'O', tag->getString("host"), '*', tag->getString("name"), tag->getString("type"), '0');
+ stats.AddRow(243, 'O', ifo->GetConfig()->getString("host"), '*', ifo->GetName(), ifo->GetType(), '0');
}
}
break;
@@ -329,23 +328,21 @@ void CommandStats::DoStats(Stats::Context& stats)
{
for (const auto& [_, tag] : ServerInstance->Config->OperTypes)
{
- tag->init();
-
std::string umodes;
for (const auto& [__, mh] : ServerInstance->Modes.GetModes(MODETYPE_USER))
{
- if (mh->NeedsOper() && tag->AllowedUserModes[ModeParser::GetModeIndex(mh->GetModeChar())])
+ if (mh->NeedsOper() && tag->CanUseMode(mh))
umodes.push_back(mh->GetModeChar());
}
std::string cmodes;
for (const auto& [__, mh] : ServerInstance->Modes.GetModes(MODETYPE_CHANNEL))
{
- if (mh->NeedsOper() && tag->AllowedUserModes[ModeParser::GetModeIndex(mh->GetModeChar())])
+ if (mh->NeedsOper() && tag->CanUseMode(mh))
cmodes.push_back(mh->GetModeChar());
}
- stats.AddRow(243, 'O', tag->name, umodes, cmodes);
+ stats.AddRow(243, 'O', tag->GetName(), umodes, cmodes);
}
}
break;
diff --git a/src/coremods/core_whois.cpp b/src/coremods/core_whois.cpp
index 496eb9a5b..23c0f90b2 100644
--- a/src/coremods/core_whois.cpp
+++ b/src/coremods/core_whois.cpp
@@ -228,7 +228,7 @@ void CommandWhois::DoWhois(LocalUser* user, User* dest, time_t signon, unsigned
if (genericoper)
whois.SendLine(RPL_WHOISOPERATOR, dest->server->IsService() ? "is a network service" : "is a server operator");
else
- whois.SendLine(RPL_WHOISOPERATOR, InspIRCd::Format("is %s %s on %s", (strchr("AEIOUaeiou",dest->oper->name[0]) ? "an" : "a"), dest->oper->name.c_str(), ServerInstance->Config->Network.c_str()));
+ whois.SendLine(RPL_WHOISOPERATOR, InspIRCd::Format("is %s %s on %s", (strchr("AEIOUaeiou",dest->oper->GetType()[0]) ? "an" : "a"), dest->oper->GetType().c_str(), ServerInstance->Config->Network.c_str()));
}
if (whois.IsSelfWhois() || user->HasPrivPermission("users/auspex"))
diff --git a/src/mode.cpp b/src/mode.cpp
index f2db07af1..ba60cafbe 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -303,7 +303,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
if (user->IsOper())
{
user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to %sset %s mode %c",
- user->oper->name.c_str(), mcitem.adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
+ user->oper->GetType().c_str(), mcitem.adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
}
else
{
diff --git a/src/modules.cpp b/src/modules.cpp
index a2fcb3059..575c54211 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -106,9 +106,6 @@ void Module::OnPreRehash(User*, const std::string&) { DetachEvent(I_OnPreRehash
void Module::OnModuleRehash(User*, const std::string&) { DetachEvent(I_OnModuleRehash); }
ModResult Module::OnUserPreJoin(LocalUser*, Channel*, const std::string&, std::string&, const std::string&, bool) { DetachEvent(I_OnUserPreJoin); return MOD_RES_PASSTHRU; }
void Module::OnMode(User*, User*, Channel*, const Modes::ChangeList&, ModeParser::ModeProcessFlag) { DetachEvent(I_OnMode); }
-void Module::OnOper(User*) { DetachEvent(I_OnOper); }
-void Module::OnPostOper(User*) { DetachEvent(I_OnPostOper); }
-void Module::OnPostDeoper(User*) { DetachEvent(I_OnPostDeoper); }
ModResult Module::OnUserPreInvite(User*, User*, Channel*, time_t) { DetachEvent(I_OnUserPreInvite); return MOD_RES_PASSTHRU; }
ModResult Module::OnUserPreMessage(User*, const MessageTarget&, MessageDetails&) { DetachEvent(I_OnUserPreMessage); return MOD_RES_PASSTHRU; }
ModResult Module::OnUserPreNick(LocalUser*, const std::string&) { DetachEvent(I_OnUserPreNick); return MOD_RES_PASSTHRU; }
@@ -165,6 +162,11 @@ void Module::OnServiceAdd(ServiceProvider&) { DetachEvent(I_OnServiceAdd); }
void Module::OnServiceDel(ServiceProvider&) { DetachEvent(I_OnServiceDel); }
ModResult Module::OnUserWrite(LocalUser*, ClientProtocol::Message&) { DetachEvent(I_OnUserWrite); return MOD_RES_PASSTHRU; }
void Module::OnShutdown(const std::string& reason) { DetachEvent(I_OnShutdown); }
+ModResult Module::OnPreOperLogin(LocalUser*, const std::shared_ptr<OperAccount>&) { DetachEvent(I_OnPreOperLogin); return MOD_RES_PASSTHRU; }
+void Module::OnOperLogin(User*, const std::shared_ptr<OperAccount>&) { DetachEvent(I_OnOperLogin); }
+void Module::OnPostOperLogin(User*) { DetachEvent(I_OnPostOperLogin); }
+void Module::OnOperLogout(User*) { DetachEvent(I_OnOperLogout); }
+void Module::OnPostOperLogout(User*, const std::shared_ptr<OperAccount>&) { DetachEvent(I_OnPostOperLogout); }
ServiceProvider::ServiceProvider(Module* Creator, const std::string& Name, ServiceType Type)
: creator(Creator), name(Name), service(Type)
diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp
index c924f55e5..10ec6ca4b 100644
--- a/src/modules/m_check.cpp
+++ b/src/modules/m_check.cpp
@@ -134,6 +134,19 @@ class CommandCheck final
return ret;
}
+ static std::string GetAllowedOperOnlyCommands(LocalUser* user)
+ {
+ std::string ret;
+ for (const auto& [_, cmd] : ServerInstance->Parser.GetCommands())
+ {
+ if (cmd->access_needed == CmdAccess::OPERATOR && user->HasCommandPermission(cmd->name))
+ ret += cmd->name + " ";
+ }
+ if (!ret.empty())
+ ret.pop_back();
+ return ret;
+ }
+
static std::string GetAllowedOperOnlyModes(LocalUser* user, ModeType modetype)
{
std::string ret;
@@ -209,15 +222,15 @@ public:
if (targetuser->IsOper())
{
- /* user is an oper of type ____ */
- context.Write("opertype", targetuser->oper->name);
+ context.Write("oper", targetuser->oper->GetName());
+ context.Write("opertype", targetuser->oper->GetType());
if (localtarget)
{
context.Write("chanmodeperms", GetAllowedOperOnlyModes(localtarget, MODETYPE_CHANNEL));
context.Write("usermodeperms", GetAllowedOperOnlyModes(localtarget, MODETYPE_USER));
context.Write("snomaskperms", GetAllowedOperOnlySnomasks(localtarget));
- context.Write("commandperms", targetuser->oper->AllowedOperCommands.ToString());
- context.Write("permissions", targetuser->oper->AllowedPrivs.ToString());
+ context.Write("commandperms", GetAllowedOperOnlyCommands(localtarget));
+ context.Write("permissions", localtarget->oper->GetPrivileges());
}
}
diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp
index bcad9bf31..cb8b3a462 100644
--- a/src/modules/m_httpd_stats.cpp
+++ b/src/modules/m_httpd_stats.cpp
@@ -274,7 +274,7 @@ namespace Stats
}
if (u->IsOper())
- serializer.Attribute("opertype", u->oper->name);
+ serializer.Attribute("opertype", u->oper->GetType());
LocalUser* lu = IS_LOCAL(u);
if (lu)
diff --git a/src/modules/m_ldapoper.cpp b/src/modules/m_ldapoper.cpp
index 78a235919..57e570d31 100644
--- a/src/modules/m_ldapoper.cpp
+++ b/src/modules/m_ldapoper.cpp
@@ -85,16 +85,16 @@ public:
void OnResult(const LDAPResult& r) override
{
auto user = ServerInstance->Users.FindUUID(uid);
- ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->oper_blocks.find(opername);
+ auto iter = ServerInstance->Config->OperAccounts.find(opername);
- if (!user || iter == ServerInstance->Config->oper_blocks.end())
+ if (!user || iter == ServerInstance->Config->OperAccounts.end())
{
Fallback();
delete this;
return;
}
- user->Oper(iter->second);
+ user->OperLogin(iter->second);
delete this;
}
};
@@ -219,15 +219,11 @@ public:
const std::string& opername = parameters[0];
const std::string& password = parameters[1];
- ServerConfig::OperIndex::const_iterator it = ServerInstance->Config->oper_blocks.find(opername);
- if (it == ServerInstance->Config->oper_blocks.end())
+ auto it = ServerInstance->Config->OperAccounts.find(opername);
+ if (it == ServerInstance->Config->OperAccounts.end())
return MOD_RES_PASSTHRU;
- std::shared_ptr<ConfigTag> tag = it->second->oper_block;
- if (!tag)
- return MOD_RES_PASSTHRU;
-
- std::string acceptedhosts = tag->getString("host");
+ std::string acceptedhosts = it->second->GetConfig()->getString("host");
if (!InspIRCd::MatchMask(acceptedhosts, user->MakeHost(), user->MakeHostIP()))
return MOD_RES_PASSTHRU;
diff --git a/src/modules/m_operchans.cpp b/src/modules/m_operchans.cpp
index 61e430633..e6c53bb12 100644
--- a/src/modules/m_operchans.cpp
+++ b/src/modules/m_operchans.cpp
@@ -54,7 +54,7 @@ public:
return false;
// Replace spaces with underscores as they're prohibited in mode parameters.
- std::string opername(user->oper->name);
+ std::string opername(user->oper->GetType());
stdalgo::string::replace_all(opername, space, underscore);
return InspIRCd::Match(opername, text);
}
diff --git a/src/modules/m_operjoin.cpp b/src/modules/m_operjoin.cpp
index e44224f4c..2608dcca3 100644
--- a/src/modules/m_operjoin.cpp
+++ b/src/modules/m_operjoin.cpp
@@ -52,7 +52,7 @@ public:
operChans.push_back(channame);
}
- void OnPostOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
LocalUser* localuser = IS_LOCAL(user);
if (!localuser)
@@ -64,7 +64,7 @@ public:
Channel::JoinUser(localuser, operchan, override);
}
- irc::commasepstream ss(localuser->oper->getConfig("autojoin"));
+ irc::commasepstream ss(localuser->oper->GetConfig()->getString("autojoin"));
for (std::string channame; ss.GetToken(channame); )
{
if (ServerInstance->Channels.IsChannel(channame))
diff --git a/src/modules/m_operlevels.cpp b/src/modules/m_operlevels.cpp
index 04c8e32e0..7b0c7a903 100644
--- a/src/modules/m_operlevels.cpp
+++ b/src/modules/m_operlevels.cpp
@@ -41,8 +41,8 @@ public:
// oper killing an oper?
if (dest->IsOper() && source->IsOper())
{
- unsigned long dest_level = ConvToNum<unsigned long>(dest->oper->getConfig("level"));
- unsigned long source_level = ConvToNum<unsigned long>(source->oper->getConfig("level"));
+ unsigned long dest_level = dest->oper->GetConfig()->getUInt("level", 0);
+ unsigned long source_level = source->oper->GetConfig()->getUInt("level", 0);
if (dest_level > source_level)
{
diff --git a/src/modules/m_opermodes.cpp b/src/modules/m_opermodes.cpp
index 2d7c39539..e0911986c 100644
--- a/src/modules/m_opermodes.cpp
+++ b/src/modules/m_opermodes.cpp
@@ -35,12 +35,12 @@ public:
{
}
- void OnPostOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
if (!IS_LOCAL(user))
return; // We don't handle remote users.
- const std::string opermodes = user->oper->getConfig("modes");
+ const std::string opermodes = user->oper->GetConfig()->getString("modes");
if (opermodes.empty())
return; // We don't have any modes to set.
diff --git a/src/modules/m_opermotd.cpp b/src/modules/m_opermotd.cpp
index 208496eae..c6cdd691d 100644
--- a/src/modules/m_opermotd.cpp
+++ b/src/modules/m_opermotd.cpp
@@ -93,7 +93,7 @@ public:
{
}
- void OnOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
if (onoper && IS_LOCAL(user))
cmd.ShowOperMOTD(user, false);
diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp
index e44408f03..a3fae72e4 100644
--- a/src/modules/m_operprefix.cpp
+++ b/src/modules/m_operprefix.cpp
@@ -104,7 +104,7 @@ public:
ServerInstance->Modes.Process(ServerInstance->FakeClient, memb->chan, nullptr, changelist);
}
- void OnPostOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
if (IS_LOCAL(user) && (!user->IsModeSet(hideopermode)))
SetOperPrefix(user, true);
@@ -114,7 +114,7 @@ public:
{
// m_opermodes may set +H on the oper to hide him, we don't want to set the oper prefix in that case
Module* opermodes = ServerInstance->Modules.Find("opermodes");
- ServerInstance->Modules.SetPriority(this, I_OnPostOper, PRIORITY_AFTER, opermodes);
+ ServerInstance->Modules.SetPriority(this, I_OnPostOperLogin, PRIORITY_AFTER, opermodes);
}
};
diff --git a/src/modules/m_override.cpp b/src/modules/m_override.cpp
index f74453a65..348889de5 100644
--- a/src/modules/m_override.cpp
+++ b/src/modules/m_override.cpp
@@ -162,9 +162,7 @@ public:
if (!source->IsModeSet(ou))
return false;
- std::string tokenlist = source->oper->getConfig("override");
- // its defined or * is set, return its value as a boolean for if the token is set
- return ((tokenlist.find(token, 0) != std::string::npos) || (tokenlist.find('*', 0) != std::string::npos));
+ return TokenList(source->oper->GetConfig()->getString("override")).Contains(token);
}
ModResult OnPreTopicChange(User* source, Channel* channel, const std::string& topic) override
diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h
index 8e8e31f94..3acbea5f6 100644
--- a/src/modules/m_spanningtree/commands.h
+++ b/src/modules/m_spanningtree/commands.h
@@ -139,7 +139,7 @@ public:
: public CmdBuilder
{
public:
- Builder(User* user);
+ Builder(User* user, const std::shared_ptr<OperAccount>& oper);
};
};
diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp
index efcac01c7..1cfaae9c7 100644
--- a/src/modules/m_spanningtree/main.cpp
+++ b/src/modules/m_spanningtree/main.cpp
@@ -505,7 +505,7 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user)
CommandUID::Builder(user).Broadcast();
if (user->IsOper())
- CommandOpertype::Builder(user).Broadcast();
+ CommandOpertype::Builder(user, user->oper).Broadcast();
for (const auto& [item, obj] : user->GetExtList())
{
@@ -772,14 +772,14 @@ restart:
}
}
-void ModuleSpanningTree::OnOper(User* user)
+void ModuleSpanningTree::OnOperLogin(User* user, const std::shared_ptr<OperAccount>& oper)
{
if (!user->IsFullyConnected() || !IS_LOCAL(user))
return;
// Note: The protocol does not allow direct umode +o;
// sending OPERTYPE infers +o modechange locally.
- CommandOpertype::Builder(user).Broadcast();
+ CommandOpertype::Builder(user, oper).Broadcast();
}
void ModuleSpanningTree::OnAddLine(User* user, XLine* x)
diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h
index dd2805557..539803a68 100644
--- a/src/modules/m_spanningtree/main.h
+++ b/src/modules/m_spanningtree/main.h
@@ -196,7 +196,7 @@ public:
void OnUserKick(User* source, Membership* memb, const std::string& reason, CUList& excepts) override;
void OnPreRehash(User* user, const std::string& parameter) override;
void ReadConfig(ConfigStatus& status) override;
- void OnOper(User* user) override;
+ void OnOperLogin(User* user, const std::shared_ptr<OperAccount>& oper) override;
void OnAddLine(User* u, XLine* x) override;
void OnDelLine(User* u, XLine* x) override;
ModResult OnStats(Stats::Context& stats) override;
diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp
index 5dcc88504..4664111c2 100644
--- a/src/modules/m_spanningtree/netburst.cpp
+++ b/src/modules/m_spanningtree/netburst.cpp
@@ -282,7 +282,7 @@ void TreeSocket::SendUsers(BurstState& bs)
this->WriteLine(CommandUID::Builder(user));
if (user->IsOper())
- this->WriteLine(CommandOpertype::Builder(user));
+ this->WriteLine(CommandOpertype::Builder(user, user->oper));
if (user->IsAway())
this->WriteLine(CommandAway::Builder(user));
diff --git a/src/modules/m_spanningtree/opertype.cpp b/src/modules/m_spanningtree/opertype.cpp
index 066913e0c..0dcfdc4d4 100644
--- a/src/modules/m_spanningtree/opertype.cpp
+++ b/src/modules/m_spanningtree/opertype.cpp
@@ -32,19 +32,11 @@
*/
CmdResult CommandOpertype::HandleRemote(RemoteUser* u, CommandBase::Params& params)
{
- const std::string& opertype = params[0];
- if (!u->IsOper())
- ServerInstance->Users.all_opers.push_back(u);
-
- ModeHandler* opermh = ServerInstance->Modes.FindMode('o', MODETYPE_USER);
- if (opermh)
- u->SetMode(opermh, true);
-
- ServerConfig::OperIndex::const_iterator iter = ServerInstance->Config->OperTypes.find(opertype);
- if (iter != ServerInstance->Config->OperTypes.end())
- u->oper = iter->second;
+ auto type = ServerInstance->Config->OperTypes.find(params[0]);
+ if (type != ServerInstance->Config->OperTypes.end())
+ u->OperLogin(std::make_shared<OperAccount>(type->first, type->second, ServerInstance->Config->EmptyTag));
else
- u->oper = std::make_shared<OperInfo>(opertype);
+ u->OperLogin(std::make_shared<OperAccount>(params[0], nullptr, ServerInstance->Config->EmptyTag));
if (Utils->quiet_bursts)
{
@@ -57,13 +49,13 @@ CmdResult CommandOpertype::HandleRemote(RemoteUser* u, CommandBase::Params& para
return CmdResult::SUCCESS;
}
- ServerInstance->SNO.WriteToSnoMask('O', "From %s: User %s (%s) is now a server operator of type %s",
- u->server->GetName().c_str(), u->nick.c_str(), u->MakeHost().c_str(), opertype.c_str());
+ ServerInstance->SNO.WriteToSnoMask('O', "From %s: %s (%s) is now a server operator of type %s",
+ u->server->GetName().c_str(), u->nick.c_str(), u->MakeHost().c_str(), u->oper->GetType().c_str());
return CmdResult::SUCCESS;
}
-CommandOpertype::Builder::Builder(User* user)
+CommandOpertype::Builder::Builder(User* user, const std::shared_ptr<OperAccount>& oper)
: CmdBuilder(user, "OPERTYPE")
{
- push_last(user->oper->name);
+ push_last(oper->GetType());
}
diff --git a/src/modules/m_sqloper.cpp b/src/modules/m_sqloper.cpp
index 6323d1ef2..8eb295222 100644
--- a/src/modules/m_sqloper.cpp
+++ b/src/modules/m_sqloper.cpp
@@ -54,11 +54,9 @@ public:
void OnResult(SQL::Result& res) override
{
- ServerConfig::OperIndex& oper_blocks = ServerInstance->Config->oper_blocks;
-
- // Remove our previous blocks from oper_blocks for a clean update
+ // Remove our previous blocks from the core for a clean update
for (const auto& block : my_blocks)
- oper_blocks.erase(block);
+ ServerInstance->Config->OperAccounts.erase(block);
my_blocks.clear();
SQL::Row row;
@@ -82,11 +80,11 @@ public:
const std::string name = tag->getString("name");
// Skip both duplicate sqloper blocks and sqloper blocks that attempt to override conf blocks.
- if (oper_blocks.find(name) != oper_blocks.end())
+ if (ServerInstance->Config->OperAccounts.find(name) != ServerInstance->Config->OperAccounts.end())
continue;
const std::string type = tag->getString("type");
- ServerConfig::OperIndex::iterator tblk = ServerInstance->Config->OperTypes.find(type);
+ auto tblk = ServerInstance->Config->OperTypes.find(type);
if (tblk == ServerInstance->Config->OperTypes.end())
{
ServerInstance->Logs.Normal(MODNAME, "Sqloper block " + name + " has missing type " + type);
@@ -94,12 +92,7 @@ public:
continue;
}
- auto ifo = std::make_shared<OperInfo>(type);
-
- ifo->type_block = tblk->second->type_block;
- ifo->oper_block = std::move(tag);
- ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end());
- oper_blocks[name] = ifo;
+ ServerInstance->Config->OperAccounts[name] = std::make_shared<OperAccount>(name, tblk->second, tag);
my_blocks.push_back(name);
row.clear();
}
@@ -123,7 +116,7 @@ public:
}
}
- // Call /oper after placing all blocks from the SQL table into the config->oper_blocks list.
+ // Call /oper after placing all blocks from the SQL table into the Config->OperAccounts list.
void OperExec()
{
auto user = ServerInstance->Users.Find(uid);
@@ -199,7 +192,7 @@ public:
{
// Remove all oper blocks that were from the DB
for (const auto& block : my_blocks)
- ServerInstance->Config->oper_blocks.erase(block);
+ ServerInstance->Config->OperAccounts.erase(block);
}
ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) override
diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp
index 5366f4ddd..15b76e4f3 100644
--- a/src/modules/m_sslinfo.cpp
+++ b/src/modules/m_sslinfo.cpp
@@ -323,36 +323,16 @@ public:
return MOD_RES_PASSTHRU;
}
- ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) override
+ ModResult OnPreOperLogin(LocalUser* user, const std::shared_ptr<OperAccount>& oper) override
{
- if ((command == "OPER") && (validated))
- {
- ServerConfig::OperIndex::const_iterator i = ServerInstance->Config->oper_blocks.find(parameters[0]);
- if (i != ServerInstance->Config->oper_blocks.end())
- {
- std::shared_ptr<OperInfo> ifo = i->second;
- ssl_cert* cert = cmd.sslapi.GetCertificate(user);
-
- if (ifo->oper_block->getBool("sslonly") && !cert)
- {
- user->WriteNumeric(ERR_NOOPERHOST, "Invalid oper credentials");
- user->CommandFloodPenalty += 10000;
- ServerInstance->SNO.WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': a secure connection is required.", user->GetFullRealHost().c_str(), parameters[0].c_str());
- return MOD_RES_DENY;
- }
+ auto cert = cmd.sslapi.GetCertificate(user);
+ if (oper->GetConfig()->getBool("sslonly") && !cert)
+ return MOD_RES_DENY;
- std::string fingerprint;
- if (ifo->oper_block->readString("fingerprint", fingerprint) && (!cert || !MatchFP(cert, fingerprint)))
- {
- user->WriteNumeric(ERR_NOOPERHOST, "Invalid oper credentials");
- user->CommandFloodPenalty += 10000;
- ServerInstance->SNO.WriteGlobalSno('o', "WARNING! Failed oper attempt by %s using login '%s': their TLS client certificate fingerprint does not match.", user->GetFullRealHost().c_str(), parameters[0].c_str());
- return MOD_RES_DENY;
- }
- }
- }
+ const std::string fingerprint = oper->GetConfig()->getString("fingerprint");
+ if (!fingerprint.empty() && (!cert || !MatchFP(cert, fingerprint)))
+ return MOD_RES_DENY;
- // Let core handle it for extra stuff
return MOD_RES_PASSTHRU;
}
@@ -382,19 +362,16 @@ public:
return;
// Find an auto-oper block for this user
- for (const auto& [_, info] : ServerInstance->Config->oper_blocks)
+ for (const auto& [_, info] : ServerInstance->Config->OperAccounts)
{
- auto oper = info->oper_block;
+ const auto& oper = info->GetConfig();
if (!oper->getBool("autologin"))
continue; // No autologin for this block.
if (!InspIRCd::MatchMask(oper->getString("host"), localuser->MakeHost(), localuser->MakeHostIP()))
continue; // Host doesn't match.
- if (!MatchFP(cert, oper->getString("fingerprint")))
- continue; // Fingerprint doesn't match.
-
- user->Oper(info);
+ user->OperLogin(info);
}
}
diff --git a/src/modules/m_swhois.cpp b/src/modules/m_swhois.cpp
index 99f9007d0..06e101746 100644
--- a/src/modules/m_swhois.cpp
+++ b/src/modules/m_swhois.cpp
@@ -116,13 +116,12 @@ public:
return MOD_RES_PASSTHRU;
}
- void OnPostOper(User* user) override
+ void OnPostOperLogin(User* user) override
{
if (!IS_LOCAL(user))
return;
- std::string swhois = user->oper->getConfig("swhois");
-
+ const std::string swhois = user->oper->GetConfig()->getString("swhois");
if (!swhois.length())
return;
@@ -130,7 +129,7 @@ public:
cmd.swhois.Set(user, swhois);
}
- void OnPostDeoper(User* user) override
+ void OnPostOperLogout(User* user, const std::shared_ptr<OperAccount>& oper) override
{
std::string* swhois = cmd.swhois.Get(user);
if (!swhois)
diff --git a/src/usermanager.cpp b/src/usermanager.cpp
index 041d32d3b..da40abd5c 100644
--- a/src/usermanager.cpp
+++ b/src/usermanager.cpp
@@ -301,7 +301,7 @@ void UserManager::QuitUser(User* user, const std::string& quitmessage, const std
uuidlist.erase(user->uuid);
user->PurgeEmptyChannels();
- user->UnOper();
+ user->OperLogout();
}
void UserManager::AddClone(User* user)
diff --git a/src/users.cpp b/src/users.cpp
index f72851f19..5f99b8d90 100644
--- a/src/users.cpp
+++ b/src/users.cpp
@@ -41,7 +41,6 @@
enum
{
// From RFC 1459.
- RPL_YOUAREOPER = 381,
ERR_NICKNAMEINUSE = 433,
// From ircu.
@@ -169,15 +168,7 @@ bool User::HasModePermission(const ModeHandler* mh) const
bool LocalUser::HasModePermission(const ModeHandler* mh) const
{
- if (!this->IsOper())
- return false;
-
- const unsigned char mode = mh->GetModeChar();
- if (!ModeParser::IsModeChar(mode))
- return false;
-
- return ((mh->GetModeType() == MODETYPE_USER ? oper->AllowedUserModes : oper->AllowedChanModes))[ModeParser::GetModeIndex(mode)];
-
+ return IsOper() && oper->CanUseMode(mh);
}
/*
* users on remote servers can completely bypass all permissions based checks.
@@ -193,13 +184,7 @@ bool User::HasCommandPermission(const std::string& command) const
bool LocalUser::HasCommandPermission(const std::string& command) const
{
- // are they even an oper at all?
- if (!this->IsOper())
- {
- return false;
- }
-
- return oper->AllowedOperCommands.Contains(command);
+ return IsOper() && oper->CanUseCommand(command);
}
bool User::HasPrivPermission(const std::string& privstr) const
@@ -209,10 +194,7 @@ bool User::HasPrivPermission(const std::string& privstr) const
bool LocalUser::HasPrivPermission(const std::string& privstr) const
{
- if (!this->IsOper())
- return false;
-
- return oper->AllowedPrivs.Contains(privstr);
+ return IsOper() && oper->HasPrivilege(privstr);
}
bool User::HasSnomaskPermission(char chr) const
@@ -222,10 +204,7 @@ bool User::HasSnomaskPermission(char chr) const
bool LocalUser::HasSnomaskPermission(char chr) const
{
- if (!this->IsOper() || !ModeParser::IsModeChar(chr))
- return false;
-
- return this->oper->AllowedSnomasks[chr - 'A'];
+ return IsOper() && oper->CanUseSnomask(chr);
}
void UserIOHandler::OnDataReady()
@@ -370,113 +349,80 @@ Cullable::Result FakeUser::Cull()
return User::Cull();
}
-void User::Oper(std::shared_ptr<OperInfo> info)
+bool User::OperLogin(const std::shared_ptr<OperAccount>& account)
{
- ModeHandler* opermh = ServerInstance->Modes.FindMode('o', MODETYPE_USER);
- if (opermh)
- {
- if (this->IsModeSet(opermh))
- this->UnOper();
- this->SetMode(opermh, true);
- }
- this->oper = info;
-
- LocalUser* localuser = IS_LOCAL(this);
- if (localuser)
+ LocalUser* luser = IS_LOCAL(this);
+ if (luser && !quitting)
{
- Modes::ChangeList changelist;
- changelist.push_add(opermh);
- ClientProtocol::Events::Mode modemsg(ServerInstance->FakeClient, nullptr, localuser, changelist);
- localuser->Send(modemsg);
+ ModResult modres;
+ FIRST_MOD_RESULT(OnPreOperLogin, modres, (luser, account));
+ if (modres == MOD_RES_DENY)
+ return false; // Module rejected the oper attempt.
}
- FOREACH_MOD(OnOper, (this));
-
- std::string opername;
- if (info->oper_block)
- opername = info->oper_block->getString("name");
+ // If this user is already logged in to an oper account then log them out.
+ if (IsOper())
+ OperLogout();
- ServerInstance->SNO.WriteToSnoMask('o', "%s (%s) is now a server operator of type %s (using oper '%s')",
- nick.c_str(), MakeHost().c_str(), oper->name.c_str(), opername.c_str());
- this->WriteNumeric(RPL_YOUAREOPER, InspIRCd::Format("You are now %s %s", strchr("aeiouAEIOU", oper->name[0]) ? "an" : "a", oper->name.c_str()));
+ FOREACH_MOD(OnOperLogin, (this, account));
- ServerInstance->Users.all_opers.push_back(this);
-
- // Expand permissions from config for faster lookup
- if (localuser)
- oper->init();
-
- FOREACH_MOD(OnPostOper, (this));
-}
-
-namespace
-{
- void ParseModeList(ModeParser::ModeStatus& modeset, std::shared_ptr<ConfigTag> tag, const std::string& field)
+ // When a user logs in we need to:
+ // 1. Set the operator account (this is what IsOper checks).
+ // 2. Set user mode o (oper) *WITHOUT* calling the mode handler.
+ // 3. Add the user to the operator list.
+ oper = account;
+ auto opermh = ServerInstance->Modes.FindMode('o', MODETYPE_USER);
+ if (opermh)
{
- for (const auto& chr : tag->getString(field))
+ SetMode(opermh, true);
+ if (luser)
{
- if (chr == '*')
- modeset.set();
- else if (ModeParser::IsModeChar(chr))
- modeset.set(ModeParser::GetModeIndex(chr));
- else
- ServerInstance->Logs.Normal("CONFIG", "'%c' is not a valid value for <class:%s>, ignoring...", chr, field.c_str());
+ Modes::ChangeList changelist;
+ changelist.push_add(opermh);
+ ClientProtocol::Events::Mode modemsg(ServerInstance->FakeClient, nullptr, luser, changelist);
+ luser->Send(modemsg);
}
}
-}
-
-void OperInfo::init()
-{
- AllowedOperCommands.Clear();
- AllowedPrivs.Clear();
- AllowedUserModes.reset();
- AllowedChanModes.reset();
- AllowedSnomasks.reset();
+ ServerInstance->Users.all_opers.push_back(this);
- for (const auto& tag : class_blocks)
- {
- AllowedOperCommands.AddList(tag->getString("commands"));
- AllowedPrivs.AddList(tag->getString("privs"));
- ParseModeList(AllowedChanModes, tag, "chanmodes");
- ParseModeList(AllowedUserModes, tag, "usermodes");
- ParseModeList(AllowedSnomasks, tag, "snomasks");
- }
+ FOREACH_MOD(OnPostOperLogin, (this));
+ return true;
}
-void User::UnOper()
+void User::OperLogout()
{
- if (!this->IsOper())
+ if (!IsOper())
return;
- /*
- * unset their oper type (what IS_OPER checks).
- * note, order is important - this must come before modes as -o attempts
- * to call UnOper. -- w00t
- */
- oper = nullptr;
+ FOREACH_MOD(OnOperLogout, (this));
- // Remove the user from the oper list
- stdalgo::vector::swaperase(ServerInstance->Users.all_opers, this);
+ // When a user logs OUT we need to:
+ // 1. Unset the operator account (this is what IsOper checks).
+ // 2. Unset user mode o (oper) *WITHOUT* calling the mode handler.
+ // 3. Remove the user from the operator list.
+ auto account = oper;
+ oper = nullptr;
// If the user is quitting we shouldn't remove any modes as it results in
// mode messages being broadcast across the network.
- if (quitting)
- return;
-
- /* Remove all oper only modes from the user when the deoper - Bug #466*/
- Modes::ChangeList changelist;
- for (const auto& [_, mh] : ServerInstance->Modes.GetModes(MODETYPE_USER))
+ if (!quitting)
{
- if (mh->NeedsOper())
- changelist.push_remove(mh);
- }
+ // Remove any oper-only modes from the user.
+ Modes::ChangeList changelist;
+ for (const auto& [_, mh] : ServerInstance->Modes.GetModes(MODETYPE_USER))
+ {
+ if (mh->NeedsOper() && IsModeSet(mh))
+ changelist.push_remove(mh);
+ }
+ ServerInstance->Modes.Process(this, nullptr, this, changelist);
- ServerInstance->Modes.Process(this, nullptr, this, changelist);
+ auto opermh = ServerInstance->Modes.FindMode('o', MODETYPE_USER);
+ if (opermh)
+ SetMode(opermh, false);
+ }
- ModeHandler* opermh = ServerInstance->Modes.FindMode('o', MODETYPE_USER);
- if (opermh)
- this->SetMode(opermh, false);
- FOREACH_MOD(OnPostDeoper, (this));
+ stdalgo::vector::swaperase(ServerInstance->Users.all_opers, this);
+ FOREACH_MOD(OnPostOperLogout, (this, account));
}
/*
@@ -1305,3 +1251,105 @@ void ConnectClass::Update(const ConnectClass::Ptr src)
type = src->type;
uniqueusername = src->uniqueusername;
}
+
+OperType::OperType(const std::string& n, const std::shared_ptr<ConfigTag>& t)
+ : config(std::make_shared<ConfigTag>("generated", FilePosition("<generated>", 0, 0)))
+ , name(n)
+{
+ if (t)
+ Configure(t, true);
+}
+
+void OperType::Configure(const std::shared_ptr<ConfigTag>& tag, bool merge)
+{
+ commands.AddList(tag->getString("commands"));
+ privileges.AddList(tag->getString("privs"));
+
+ auto modefn = [&tag](ModeParser::ModeStatus& modes, const std::string& key)
+ {
+ bool adding = true;
+ for (const auto& chr : tag->getString(key))
+ {
+ if (chr == '+' || chr == '-')
+ adding = (chr == '+');
+ else if (chr == '*' && adding)
+ modes.set();
+ else if (chr == '*' && !adding)
+ modes.reset();
+ else if (ModeParser::IsModeChar(chr))
+ modes.set(ModeParser::GetModeIndex(chr), adding);
+ }
+ };
+ modefn(chanmodes, "chanmodes");
+ modefn(usermodes, "usermodes");
+ modefn(snomasks, "snomasks");
+
+ if (merge)
+ MergeTag(tag);
+}
+
+bool OperType::CanUseCommand(const std::string& cmd) const
+{
+ return commands.Contains(cmd);
+}
+
+bool OperType::CanUseMode(const ModeHandler* mh) const
+{
+ const size_t index = ModeParser::GetModeIndex(mh->GetModeChar());
+ if (index == ModeParser::MODEID_MAX)
+ return false;
+
+ return (mh->GetModeType() == MODETYPE_USER ? usermodes : chanmodes)[index];
+}
+
+bool OperType::CanUseSnomask(unsigned char chr) const
+{
+ if ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'))
+ return snomasks[chr - 'A'];
+ return false;
+}
+
+bool OperType::HasPrivilege(const std::string& priv) const
+{
+ return privileges.Contains(priv);
+}
+
+void OperType::MergeTag(const std::shared_ptr<ConfigTag>& tag)
+{
+ for (const auto& [key, value] : tag->GetItems())
+ {
+ if (stdalgo::string::equalsci(key, "name") || stdalgo::string::equalsci(key, "type")
+ || stdalgo::string::equalsci(key, "classes"))
+ {
+ // These are meta keys for linking the oper/type/class tags.
+ continue;
+ }
+
+ if (stdalgo::string::equalsci(key, "commands") || stdalgo::string::equalsci(key, "privs")
+ || stdalgo::string::equalsci(key, "chanmodes") || stdalgo::string::equalsci(key, "usermodes")
+ || stdalgo::string::equalsci(key, "snomasks"))
+ {
+ // These have already been parsed into the object.
+ continue;
+ }
+
+ config->GetItems()[key] = value;
+ }
+}
+
+OperAccount::OperAccount(const std::string& n, const std::shared_ptr<OperType>& o, const std::shared_ptr<ConfigTag>& t)
+ : OperType(n, nullptr)
+ , type(o ? o->GetName() : n)
+{
+ if (o)
+ {
+ chanmodes = o->chanmodes;
+ commands = o->commands;
+ privileges = o->privileges;
+ snomasks = o->snomasks;
+ usermodes = o->usermodes;
+ Configure(o->GetConfig(), true);
+ }
+ Configure(t, true);
+
+}