refactored parsing xml, added handling <include> tags 43/177343/3
authorAleksy Barcz <a.barcz@partner.samsung.com>
Thu, 26 Apr 2018 14:13:32 +0000 (16:13 +0200)
committerAleksy Barcz <a.barcz@partner.samsung.com>
Fri, 27 Apr 2018 11:29:46 +0000 (13:29 +0200)
Up to now <include> tags were ignored, only <includedir> worked.
Assuming that we won't use selinux, so we can ignore includes
tagged as if_selinux_enabled.
Fixed undefined behaviour when modifying std::string.c_str() using dirname.

Change-Id: Ia56f030ec509721584dd2ccd476976ea8f66a440

src/internal/cynara.cpp
src/internal/cynara_mockup.cpp
src/internal/internal.cpp
src/internal/libdbuspolicy1-private.hpp [deleted file]
src/internal/policy.cpp
src/internal/policy.hpp
src/internal/xml_parser.cpp
src/internal/xml_parser.hpp

index 8be1c11..be3548f 100644 (file)
@@ -1,5 +1,4 @@
 #include "cynara.hpp"
-#include "libdbuspolicy1-private.hpp"
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdexcept>
index a95d160..cf7e45a 100644 (file)
@@ -1,5 +1,4 @@
 #include "cynara.hpp"
-#include "libdbuspolicy1-private.hpp"
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdexcept>
index 3c3d82b..222e4a2 100755 (executable)
@@ -25,8 +25,7 @@
 #include "policy.hpp"
 #include "naive_policy_checker.hpp"
 #include "internal.h"
-
-#include "../libdbuspolicy1-private.h"
+#include "tslog.hpp"
 
 static const char* get_str(const char* const szstr) {
        return (szstr != NULL) ? szstr : "";
@@ -36,7 +35,7 @@ int __internal_init(bool bus_type, const char* const config_name)
 {
        ldp_xml_parser::XmlParser p;
        auto err = p.parsePolicy(bus_type, get_str(config_name));
-       return err.get();
+       return err;
 }
 
 pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/src/internal/libdbuspolicy1-private.hpp b/src/internal/libdbuspolicy1-private.hpp
deleted file mode 100644 (file)
index 14b9d09..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-#ifndef _LIBDBUSPOLICY1_PRIVATE_HPP
-#define _LIBDBUSPOLICY1_PRIVATE_HPP
-
-#include <string>
-
-namespace arraySizeDetail {
-       template <class T, size_t S> constexpr size_t size(T const (&)[S]) { return S; }
-       template <class T> constexpr size_t size(std::initializer_list<T> const &l) { return l.size(); }
-}
-#define TABSIZE(...) (::arraySizeDetail::size(__VA_ARGS__))
-
-namespace {
-       /** Contains error code and string corresponding to it */
-    class ErrCode {
-        int m_err;
-        std::string m_err_str;
-        ErrCode(int e, const std::string& s) : m_err(e), m_err_str(s) {}
-        public:
-            ErrCode() : m_err(0), m_err_str("") {}
-
-            static ErrCode ok() {
-                return ErrCode(0, "OK");
-            }
-
-            template<typename T>
-            static ErrCode ok(T e) {
-                return ErrCode((e > 0) ? e : 0, "OK");
-            }
-
-            static ErrCode error(const std::string& what) {
-                return ErrCode(-1, what);
-            }
-
-            int get() const {
-                return m_err;
-            }
-
-            const std::string& get_str() const {
-                return m_err_str;
-            }
-
-            bool is_ok() const {
-                return (m_err >= 0);
-            }
-
-            bool is_true() const {
-                return (m_err > 0);
-            }
-
-            bool is_false() const {
-                return (m_err == 0);
-            }
-
-            bool is_error() const {
-                return (m_err < 0);
-            }
-    };
-} //namespace
-
-#endif
index f40407d..b4babc8 100755 (executable)
@@ -88,17 +88,6 @@ static bool field_has(const ptree::value_type& v, const std::string& substr) {
        return (v.first.find(substr) != std::string::npos);
 }
 
-void DbAdapter::updateDb(bool bus, const ptree& pt, std::vector<std::string>& incl_dirs) {
-       const auto& busconfig = pt.get_child("busconfig");
-       for (const auto& x : busconfig) {
-               if (x.first == "policy") {
-                       parsePolicy(bus, x.second);
-               } else if (x.first == "includedir") {
-                       incl_dirs.push_back(x.second.data());
-               }
-       }
-}
-
 static const std::map<std::string, Decision> str2decision{
        {"allow", Decision::ALLOW},
        {"deny", Decision::DENY},
index 428bb44..965d5a4 100755 (executable)
@@ -219,13 +219,12 @@ namespace ldp_xml_parser
        class DbAdapter {
        private:
                ItemBuilder __builder;
-               void parsePolicy(bool bus, const boost::property_tree::ptree& pt);
                void parsePolicyAttribute(const boost::property_tree::ptree::value_type& v, PolicyType&, PolicyTypeValue&);
                void parseRule(const boost::property_tree::ptree::value_type& v);
                void parseRuleAttribute(const boost::property_tree::ptree::value_type& v);
 
        public:
-               void updateDb(bool bus, const boost::property_tree::ptree& xmlTree, std::vector<std::string>& incl_dirs);
+               void parsePolicy(bool bus, const boost::property_tree::ptree& pt);
                void updateGroupDb(bool bus);
        };
 }
index afd14ca..febe723 100644 (file)
@@ -4,4 +4,156 @@
  */
 #include "xml_parser.hpp"
 
-std::set<std::string> ldp_xml_parser::XmlParser::__parsed;
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <dirent.h>
+#include <unistd.h>
+#include <cstring>
+#include <libgen.h>
+#include "tslog.hpp"
+
+using namespace ldp_xml_parser;
+using boost::property_tree::ptree;
+
+std::string expandPath(const std::string& parent_dir, const std::string& path) {
+       if (path[0] == '/') {
+               return path;
+       }
+       return parent_dir + "/" + path;
+}
+
+std::string getDir(std::string path) {
+       // dirname may modify path, so we must pass a modifiable char* to it
+       char* modifiable_path = new char[path.size() + 1];
+       strcpy(modifiable_path, path.c_str());
+       std::string ret = dirname(modifiable_path);
+       delete[] modifiable_path;
+       return ret;
+}
+
+void logError(const char* error) {
+       if (tslog::enabled()) {
+               std::cout << "Error parsing xml: " <<  error << std::endl;
+       }
+}
+
+class XmlParser::IncludeItem {
+public:
+       std::string filename;
+       bool ignore_missing{false};
+       bool ignore_always{false};
+};
+
+int XmlParser::parsePolicy(bool bus, std::string const &fname) {
+       if (tslog::enabled()) {
+               std::cout << "XmlParser::parsePolicy called with filename: " << fname << std::endl;
+       }
+
+       try {
+               parsePolicyInternal(bus, fname);
+       } catch (const boost::property_tree::xml_parser::xml_parser_error& ex) {
+               logError(ex.what());
+               return -1;
+       } catch (const boost::property_tree::ptree_error& ex) {
+               logError(ex.what());
+               return -1;
+       } catch (const std::runtime_error& ex) {
+               logError(ex.what());
+               return -1;
+       } catch (...) {
+               logError("unknown error");
+               return -1;
+       }
+       return 0;
+}
+
+void XmlParser::parsePolicyInternal(bool bus, std::string const &filename) {
+       auto included_files = parseXmlFile(bus, filename);
+       for (const auto& included_file : included_files) {
+               parsePolicyInternal(bus, included_file);
+       }
+}
+
+std::vector<std::string> XmlParser::parseXmlFile(bool bus, const std::string& filename) {
+       std::vector<std::string> included_files;
+
+       if (tslog::enabled()) {
+               std::cout << "Processing: " << filename << " ..." << std::endl;
+               if (tslog::verbose())
+                       std::cout << "=== XML PARSING BEGIN === : " << filename << '\n';
+       }
+       const std::string curr_dir = getDir(filename);
+
+       boost::property_tree::ptree pt;
+       read_xml(filename, pt);
+       if (!pt.empty()) {
+               const auto& busconfig = pt.get_child("busconfig");
+               for (const auto& x : busconfig) {
+                       if (x.first == "policy") {
+                               __adapter.parsePolicy(bus, x.second);
+                       } else if (x.first == "include") {
+                               IncludeItem item = parseIncludeItem(x.second, curr_dir);
+                               if (item.ignore_always) {
+                                       continue;
+                               }
+                               if (access(item.filename.c_str(), F_OK) != 0) {
+                                       if (item.ignore_missing) {
+                                               continue;
+                                       }
+                                       throw std::runtime_error("Missing required policy file: " + item.filename);
+                               }
+                               included_files.push_back(item.filename);
+                       } else if (x.first == "includedir") {
+                               getIncludedFiles(curr_dir, x.second.data(), included_files);
+                       }
+               }
+       }
+
+       if (tslog::enabled()) {
+               if (tslog::verbose())
+                       std::cout << "=== XML PARSING END ===\n\n";
+       }
+
+       return included_files;
+}
+
+XmlParser::IncludeItem XmlParser::parseIncludeItem(const ptree& pt, const std::string& parent_dir) {
+       IncludeItem item;
+       item.filename = expandPath(parent_dir, pt.data());
+       const auto xmlattr = pt.get_child_optional("<xmlattr>");
+       if (xmlattr) {
+               for (const auto& va : *xmlattr) {
+                       if (va.first == "ignore_missing" && va.second.data() == "yes") {
+                               item.ignore_missing = true;
+                       } else if (va.first == "if_selinux_enabled" && va.second.data() == "yes") {
+                               item.ignore_always = true;
+                       }
+               }
+       }
+       return item;
+}
+
+void XmlParser::getIncludedFiles(const std::string& parent_dir, const std::string& incldir, std::vector<std::string>& files) {
+       DIR *dir;
+       struct dirent *ent;
+       const std::string dname = expandPath(parent_dir, incldir);
+       files.clear();
+       if ((dir = opendir(dname.c_str())) != NULL) {
+               while ((ent = readdir(dir)) != NULL) {
+                       std::string s(ent->d_name);
+                       if (boost::algorithm::ends_with(s, ".conf")) {
+                               files.push_back(dname + std::string("/") + s);
+                       }
+               }
+               closedir(dir);
+
+               if (tslog::enabled()) {
+                       std::cout << "\nincludedir: " << incldir << ", " << files.size() << " included files found:\n";
+                       std::copy(files.begin(), files.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
+                       std::cout << '\n';
+               }
+       } else if (tslog::enabled()) {
+               std::cout << "could not open directory " << dname << '\n';
+       }
+}
index 82480f3..3c1b2be 100755 (executable)
 #define _XML_PARSER_HPP
 
 #include <set>
-#include <boost/algorithm/string/predicate.hpp>
 #include <boost/noncopyable.hpp>
-#include <boost/property_tree/ptree.hpp>
-#include <boost/property_tree/xml_parser.hpp>
-#include <dirent.h>
-#include <libgen.h>
-#include "libdbuspolicy1-private.hpp"
-#include "tslog.hpp"
 #include "policy.hpp"
 
 namespace ldp_xml_parser
 {
-    /** Class which have methods parsing policy rules contained in xml files */
-    class XmlParser : boost::noncopyable
-    {
-        public:
-            /** Parses given config file for declared bus type */
-            ErrCode parsePolicy(bool bus,
-                    std::string const &fname) {
-                ErrCode err = parse(bus, fname);
-                return err;
-            }
-            void updateGroupPolicy(bool bus) {
-                __adapter.updateGroupDb(bus);
-            }
+       /** Class which have methods parsing policy rules contained in xml files */
+       class XmlParser : private boost::noncopyable
+       {
+       public:
+               /** Parses given config file for declared bus type */
+               int parsePolicy(bool bus, std::string const &fname);
 
-        private:
-            /** Vector containing parsed policy */
-            static std::set<std::string> __parsed;
+               void updateGroupPolicy(bool bus) {
+                       __adapter.updateGroupDb(bus);
+               }
 
-            /** Adapter which allows to access parsed policies */
-            DbAdapter __adapter;
+       private:
+               class IncludeItem;
 
-            /** Parses config file and all files included in it */
-            ErrCode parse(bool bus, std::string const &filename) {
-                ErrCode err;
-                std::vector<std::string> incl_files;
+               /** Adapter which allows to access parsed policies */
+               DbAdapter __adapter;
 
-                err = parse(bus, filename, incl_files);
-                if (err.is_ok())
-                    for (const auto& x : incl_files) {
-                        err = parse(bus, x, incl_files);
-                        if (err.is_error()) break;
-                    }
-                return err;
-            }
-            /** Parses given xml file and files included in it */
-            ErrCode parse(bool bus, const std::string& filename, std::vector<std::string>& included_files) {
-                std::pair<ErrCode, std::string> errparam;
-                               std::vector<std::string> incl_dirs;
-                               if (tslog::verbose())
-                                       std::cout << "=== XML PARSING BEGIN === : " << filename << '\n';
+               /** Parses config file and all files included in it (recursively) */
+               void parsePolicyInternal(bool bus, std::string const &filename);
 
-                errparam = parseXml(bus, filename, incl_dirs);
-                               for (unsigned i = 0; i < incl_dirs.size(); i++) {
-                                       getIncludedFiles(filename, incl_dirs[i], included_files);
-                               }
+               /** Parses config file and returns all files included in it */
+               std::vector<std::string> parseXmlFile(bool bus, const std::string& filename);
 
-                               if (tslog::enabled()) {
-                                       if (tslog::verbose())
-                                               std::cout << "=== XML PARSING END ===\n\n";
-                                       std::cout << "Processing of " << filename << " -> [" << errparam.first.get() << ", " << errparam.first.get_str() << "]\n";
-                               }
-                return errparam.first;
-            }
+               /** Parses <include> element */
+               IncludeItem parseIncludeItem(const boost::property_tree::ptree& pt, const std::string& parent_dir);
 
-            /** Get all the .conf files within included subdirectory, POSIX style as boost::filesystem is not header-only */
-            void getIncludedFiles(const std::string& filename, const std::string& incldir, std::vector<std::string>& files) {
-                               DIR *dir;
-                               struct dirent *ent;
-                               std::string dname = dirname(const_cast<char*>(filename.c_str()));
-                               if (incldir[0] != '/')
-                                       dname += (std::string("/") + incldir);
-                               else
-                                       dname = incldir;
-                               files.clear();
-                               if ((dir = opendir(dname.c_str())) != NULL) {
-                                       while ((ent = readdir(dir)) != NULL) {
-                                               std::string s(ent->d_name);
-                                               if (boost::algorithm::ends_with(s, ".conf")) {
-                                                       files.push_back(dname + std::string("/") + s);
-                                               }
-                                       }
-                                       closedir(dir);
-
-                                       if (tslog::enabled()) {
-                                               std::cout << "\nincludedir for " << filename << " is " << incldir << ", " << files.size() << " included files found:\n";
-                                               std::copy(files.begin(), files.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
-                                               std::cout << '\n';
-                                       }
-                               } else if (tslog::enabled()) {
-                                       std::cout << "could not open directory " << dname << '\n';
-                               }
-            }
-               /** Acceses given configuration file/files */
-               std::pair<ErrCode, std::string> parseXml(bool bus, const std::string& filename, std::vector<std::string>& incl_dirs) {
-                std::pair<ErrCode, std::string> ret;
-
-                               if (__parsed.insert(filename).second)
-                                       try {
-                                               boost::property_tree::ptree pt;
-                                               read_xml(filename, pt);
-                                               if (!pt.empty()) {
-                            __adapter.updateDb(bus, pt, incl_dirs);
-                                               }
-                                       } catch (const boost::property_tree::xml_parser::xml_parser_error& ex) {
-                                               ret.first = ErrCode::error(ex.what());
-                                       } catch (const boost::property_tree::ptree_error& ex) {
-                                               ret.first = ErrCode::error(ex.what());
-                                       } catch (...) {
-                                               ret.first = ErrCode::error(filename + std::string(": unknown error while parsing XML"));
-                                       }
-
-                return ret;
-            }
-    };
+               /** Get all the .conf files within included subdirectory, POSIX style as boost::filesystem is not header-only */
+               void getIncludedFiles(const std::string& parent_dir, const std::string& incldir, std::vector<std::string>& files);
+       };
 } //namespace
 
 #endif