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
#include "cynara.hpp"
-#include "libdbuspolicy1-private.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <stdexcept>
#include "cynara.hpp"
-#include "libdbuspolicy1-private.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <stdexcept>
#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 : "";
{
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;
+++ /dev/null
-/*
- * 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
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},
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);
};
}
*/
#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';
+ }
+}
#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