]> granicus.if.org Git - icinga2/commitdiff
Escape special characters in repository file names
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 10 Dec 2014 12:20:16 +0000 (13:20 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 10 Dec 2014 12:20:16 +0000 (13:20 +0100)
fixes #7618

lib/base/utility.cpp
lib/base/utility.hpp
lib/cli/repositoryutility.cpp
lib/cli/repositoryutility.hpp

index 0745e1265c0b8eb85211b7d817324f35a548c76b..31c766b920d7c109ca1f42268ff4a78c45327a07 100644 (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();
+}
index 680594a77064d23c1682bd0c84feff4db9f0eec7..8300d0353c7a583d717a99822a0306dbbd2fc3df 100644 (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);
 
index b9d87c2906749da219652f4504dafcfc1b4b9322..7c57984d9d9d1d1a9466d2922b8b1a8facabb5f5 100644 (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
index f4a6e302a65c4a1332d9fb6bcaa1d6458b5ae447..0ce78abd4816722f6c13578fe74ab5b31ff35c0e 100644 (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);
 };
 
 }