From 5287af979e5abffb2cfcdadb9a7663b42a5c43e5 Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Thu, 17 Aug 2017 18:32:19 +0100 Subject: Add a class which encapsulates the concept of token lists. --- include/configreader.h | 6 +-- include/token_list.h | 65 ++++++++++++++++++++++++++++ src/inspstring.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ src/modules/m_check.cpp | 6 +-- src/users.cpp | 33 +++------------ 5 files changed, 186 insertions(+), 34 deletions(-) create mode 100644 include/token_list.h diff --git a/include/configreader.h b/include/configreader.h index 9fcb9c6a3..fc8c99d62 100644 --- a/include/configreader.h +++ b/include/configreader.h @@ -31,6 +31,7 @@ #include "modules.h" #include "socketengine.h" #include "socket.h" +#include "token_list.h" /** Structure representing a single \ in config */ class CoreExport ConfigTag : public refcountbase @@ -165,9 +166,8 @@ struct CommandLineConf class CoreExport OperInfo : public refcountbase { public: - typedef insp::flat_set PrivSet; - PrivSet AllowedOperCommands; - PrivSet AllowedPrivs; + TokenList AllowedOperCommands; + TokenList AllowedPrivs; /** Allowed user modes from oper classes. */ std::bitset<64> AllowedUserModes; diff --git a/include/token_list.h b/include/token_list.h new file mode 100644 index 000000000..ffa3b89e6 --- /dev/null +++ b/include/token_list.h @@ -0,0 +1,65 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2017 Peter Powell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#pragma once + +#include "compat.h" + +class CoreExport TokenList +{ + private: + /** Whether this list includes all tokens by default. */ + bool permissive; + + /** Either the tokens to exclude if in permissive mode or the tokens to include if in strict mode. */ + insp::flat_set tokens; + + public: + /** Adds a space-delimited list of tokens to the token list. + * @param tokenlist The list of space-delimited tokens to add. + */ + void AddList(const std::string& tokenlist); + + /** Adds a single token to the token list. + * @param token The token to add. + */ + void Add(const std::string& token); + + /** Removes all tokens from the token list. */ + void Clear(); + + /** Determines whether the specified token exists in the token list. + * @param token The token to search for. + */ + bool Contains(const std::string& token) const; + + /** Removes the specified token from the token list. + * @param token The token to remove. + */ + void Remove(const std::string& token); + + /** Retrieves a string which represents the contents of this token list. */ + std::string ToString() const; + + /** Determines whether the specified token list contains the same tokens as this instance. + * @param other The tokenlist to compare against. + * @return True if the token lists are equal; otherwise, false. + */ + bool operator==(const TokenList& other) const; +}; diff --git a/src/inspstring.cpp b/src/inspstring.cpp index b59492738..283c00d5b 100644 --- a/src/inspstring.cpp +++ b/src/inspstring.cpp @@ -124,3 +124,113 @@ bool InspIRCd::TimingSafeCompare(const std::string& one, const std::string& two) return (diff == 0); } + +void TokenList::AddList(const std::string& tokenlist) +{ + std::string token; + irc::spacesepstream tokenstream(tokenlist); + while (tokenstream.GetToken(token)) + { + if (token[0] == '-') + Remove(token.substr(1)); + else + Add(token); + } + +} +void TokenList::Add(const std::string& token) +{ + // If the token is empty or contains just whitespace it is invalid. + if (token.empty() || token.find_first_not_of(" \t") == std::string::npos) + return; + + // If the token is a wildcard entry then permissive mode has been enabled. + if (token == "*") + { + permissive = true; + tokens.clear(); + return; + } + + // If we are in permissive mode then remove the token from the token list. + // Otherwise, add it to the token list. + if (permissive) + tokens.erase(token); + else + tokens.insert(token); +} + +void TokenList::Clear() +{ + permissive = false; + tokens.clear(); +} + +bool TokenList::Contains(const std::string& token) const +{ + // If we are in permissive mode and the token is in the list + // then we don't have it. + if (permissive && tokens.find(token) != tokens.end()) + return false; + + // If we are not in permissive mode and the token is not in + // the list then we don't have it. + if (!permissive && tokens.find(token) == tokens.end()) + return false; + + // We have the token! + return true; +} + +void TokenList::Remove(const std::string& token) +{ + // If the token is empty or contains just whitespace it is invalid. + if (token.empty() || token.find_first_not_of(" \t") == std::string::npos) + return; + + // If the token is a wildcard entry then permissive mode has been disabled. + if (token == "*") + { + permissive = false; + tokens.clear(); + return; + } + + // If we are in permissive mode then add the token to the token list. + // Otherwise, remove it from the token list. + if (permissive) + tokens.insert(token); + else + tokens.erase(token); +} + +std::string TokenList::ToString() const +{ + std::string buffer(permissive ? "*" : "-*"); + for (insp::flat_set::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + buffer.push_back(' '); + buffer.append(*iter); + } + return buffer; +} + +bool TokenList::operator==(const TokenList& other) const +{ + // Both sets must be in the same mode to be equal. + if (permissive != other.permissive) + return false; + + // Both sets must be the same size to be equal. + if (tokens.size() != other.tokens.size()) + return false; + + for (insp::flat_set::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + // Both sets must contain the same tokens to be equal. + if (other.tokens.find(*iter) == other.tokens.end()) + return false; + } + + return true; +} diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index b442dea9c..e401c79f1 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -197,12 +197,10 @@ class CommandCheck : public Command context.Write("modeperms", "user=" + umodes + " channel=" + cmodes); CheckContext::List opcmdlist(context, "commandperms"); - for (OperInfo::PrivSet::const_iterator i = oper->AllowedOperCommands.begin(); i != oper->AllowedOperCommands.end(); ++i) - opcmdlist.Add(*i); + opcmdlist.Add(oper->AllowedOperCommands.ToString()); opcmdlist.Flush(); CheckContext::List privlist(context, "permissions"); - for (OperInfo::PrivSet::const_iterator i = oper->AllowedPrivs.begin(); i != oper->AllowedPrivs.end(); ++i) - privlist.Add(*i); + opcmdlist.Add(oper->AllowedPrivs.ToString()); privlist.Flush(); } } diff --git a/src/users.cpp b/src/users.cpp index 397a13267..f7cd00a07 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -189,12 +189,7 @@ bool LocalUser::HasPermission(const std::string &command) return false; } - if (oper->AllowedOperCommands.find(command) != oper->AllowedOperCommands.end()) - return true; - else if (oper->AllowedOperCommands.find("*") != oper->AllowedOperCommands.end()) - return true; - - return false; + return oper->AllowedOperCommands.Contains(command); } bool User::HasPrivPermission(const std::string &privstr, bool noisy) @@ -211,14 +206,8 @@ bool LocalUser::HasPrivPermission(const std::string &privstr, bool noisy) return false; } - if (oper->AllowedPrivs.find(privstr) != oper->AllowedPrivs.end()) - { + if (oper->AllowedPrivs.Contains(privstr)) return true; - } - else if (oper->AllowedPrivs.find("*") != oper->AllowedPrivs.end()) - { - return true; - } if (noisy) this->WriteNotice("Oper type " + oper->name + " does not have access to priv " + privstr); @@ -375,8 +364,8 @@ void User::Oper(OperInfo* info) void OperInfo::init() { - AllowedOperCommands.clear(); - AllowedPrivs.clear(); + AllowedOperCommands.Clear(); + AllowedPrivs.Clear(); AllowedUserModes.reset(); AllowedChanModes.reset(); AllowedUserModes['o' - 'A'] = true; // Call me paranoid if you want. @@ -384,19 +373,9 @@ void OperInfo::init() for(std::vector >::iterator iter = class_blocks.begin(); iter != class_blocks.end(); ++iter) { ConfigTag* tag = *iter; - std::string mycmd, mypriv; - /* Process commands */ - irc::spacesepstream CommandList(tag->getString("commands")); - while (CommandList.GetToken(mycmd)) - { - AllowedOperCommands.insert(mycmd); - } - irc::spacesepstream PrivList(tag->getString("privs")); - while (PrivList.GetToken(mypriv)) - { - AllowedPrivs.insert(mypriv); - } + AllowedOperCommands.AddList(tag->getString("commands")); + AllowedPrivs.AddList(tag->getString("privs")); std::string modes = tag->getString("usermodes"); for (std::string::const_iterator c = modes.begin(); c != modes.end(); ++c) -- cgit v1.2.3