Escape special characters in repository file names

fixes #7618
This commit is contained in:
Gunnar Beutner 2014-12-10 13:20:16 +01:00
parent 705447ce18
commit c1ac548a77
4 changed files with 83 additions and 8 deletions

View File

@ -26,6 +26,7 @@
#include "base/utility.hpp"
#include "base/json.hpp"
#include "base/objectlock.hpp"
#include "base/scriptfunction.hpp"
#include <mmatch.h>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
@ -57,6 +58,9 @@ using namespace icinga;
boost::thread_specific_ptr<String> Utility::m_ThreadName;
boost::thread_specific_ptr<unsigned int> Utility::m_RandSeed;
REGISTER_SCRIPTFUNCTION(escape, &Utility::EscapeString);
REGISTER_SCRIPTFUNCTION(unescape, &Utility::UnescapeString);
/**
* Demangles a symbol name.
*
@ -1201,3 +1205,58 @@ void Utility::SaveJsonFile(const String& path, const Value& value)
<< boost::errinfo_file_name(tempPath));
}
}
static void HexEncode(char ch, std::ostream& os)
{
const char *hex_chars = "0123456789ABCDEF";
os << hex_chars[ch >> 4 & 0x0f];
os << hex_chars[ch & 0x0f];
}
static int HexDecode(char hc)
{
if (hc >= '0' && hc <= '9')
return hc - '0';
else if (hc >= 'a' && hc <= 'f')
return hc - 'a' + 10;
else if (hc >= 'A' && hc <= 'F')
return hc - 'A' + 10;
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid hex character."));
}
String Utility::EscapeString(const String& s, const String& chars)
{
std::ostringstream result;
BOOST_FOREACH(char ch, s) {
if (chars.FindFirstOf(ch) != String::NPos || ch == '%') {
result << '%';
HexEncode(ch, result);
} else
result << ch;
}
return result.str();
}
String Utility::UnescapeString(const String& s)
{
std::ostringstream result;
for (String::SizeType i = 0; i < s.GetLength(); i++) {
if (s[i] == '%') {
if (i + 2 > s.GetLength() - 1)
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid escape sequence."));
char ch = HexDecode(s[i + 1]) * 16 + HexDecode(s[i + 2]);
result << ch;
i += 2;
} else
result << s[i];
}
return result.str();
}

View File

@ -115,6 +115,9 @@ public:
static String EscapeShellCmd(const String& s);
static String EscapeShellArg(const String& s);
static String EscapeString(const String& s, const String& chars);
static String UnescapeString(const String& s);
static void SetThreadName(const String& name, bool os = true);
static String GetThreadName(void);

View File

@ -86,7 +86,7 @@ String RepositoryUtility::GetRepositoryObjectConfigPath(const String& type, cons
if (type == "Host")
path += "hosts";
else if (type == "Service")
path += "hosts/" + object->Get("host_name");
path += "hosts/" + EscapeName(object->Get("host_name"));
else if (type == "Zone")
path += "zones";
else if (type == "Endpoint")
@ -116,7 +116,7 @@ String RepositoryUtility::GetRepositoryObjectConfigFilePath(const String& type,
{
String path = GetRepositoryObjectConfigPath(type, object);
path += "/" + object->Get("name") + ".conf";
path += "/" + EscapeName(object->Get("name")) + ".conf";
return path;
}
@ -154,6 +154,7 @@ void RepositoryUtility::PrintObjects(std::ostream& fp, const String& type)
String file = Utility::BaseName(object);
boost::algorithm::replace_all(file, ".conf", "");
file = UnescapeName(file);
fp << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << type << ConsoleColorTag(Console_Normal)
<< " '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << file << ConsoleColorTag(Console_Normal) << "'";
@ -164,7 +165,7 @@ void RepositoryUtility::PrintObjects(std::ostream& fp, const String& type)
std::vector<String> tokens;
boost::algorithm::split(tokens, prefix, boost::is_any_of("/"));
String host_name = tokens[tokens.size()-1];
String host_name = UnescapeName(tokens[tokens.size()-1]);
fp << " (on " << ConsoleColorTag(Console_ForegroundMagenta | Console_Bold) << "Host" << ConsoleColorTag(Console_Normal)
<< " '" << ConsoleColorTag(Console_ForegroundBlue | Console_Bold) << host_name << ConsoleColorTag(Console_Normal) << "')";
@ -205,9 +206,9 @@ bool RepositoryUtility::AddObject(const String& name, const String& type, const
String pattern;
if (type == "Service")
pattern = attrs->Get("host_name") + "/" + name + ".conf";
pattern = EscapeName(attrs->Get("host_name")) + "/" + EscapeName(name) + ".conf";
else
pattern = name + ".conf";
pattern = EscapeName(name) + ".conf";
BOOST_FOREACH(const String& object_path, object_paths) {
if (object_path.Contains(pattern)) {
@ -421,14 +422,14 @@ Dictionary::Ptr RepositoryUtility::GetObjectFromRepositoryChangeLog(const String
/* internal implementation when changes are committed */
bool RepositoryUtility::AddObjectInternal(const String& name, const String& type, const Dictionary::Ptr& attrs)
{
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + name + ".conf";
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + EscapeName(name) + ".conf";
return WriteObjectToRepository(path, name, type, attrs);
}
bool RepositoryUtility::RemoveObjectInternal(const String& name, const String& type, const Dictionary::Ptr& attrs)
{
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + name + ".conf";
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + EscapeName(name) + ".conf";
if (!Utility::PathExists(path)) {
Log(LogWarning, "cli")
@ -492,7 +493,7 @@ bool RepositoryUtility::RemoveObjectFileInternal(const String& path)
bool RepositoryUtility::SetObjectAttributeInternal(const String& name, const String& type, const String& key, const Value& val, const Dictionary::Ptr& attrs)
{
//TODO
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + name + ".conf";
String path = GetRepositoryObjectConfigPath(type, attrs) + "/" + EscapeName(name) + ".conf";
Dictionary::Ptr obj = GetObjectFromRepository(path); //TODO
@ -550,6 +551,15 @@ Dictionary::Ptr RepositoryUtility::GetObjectFromRepository(const String& filenam
return Dictionary::Ptr();
}
String RepositoryUtility::EscapeName(const String& name)
{
return Utility::EscapeString(name, "<>:\"/\\|?*");
}
String RepositoryUtility::UnescapeName(const String& name)
{
return Utility::UnescapeString(name);
}
/*
* collect functions

View File

@ -95,6 +95,9 @@ private:
static void SerializeObject(std::ostream& fp, const String& name, const String& type, const Dictionary::Ptr& object);
static void FormatValue(std::ostream& fp, const Value& val);
static void FormatArray(std::ostream& fp, const Array::Ptr& arr);
static String EscapeName(const String& name);
static String UnescapeName(const String& name);
};
}