Merge "printer: print FileIdentifier" into tizen_5.5
[platform/core/system/libdbuspolicy.git] / src / internal / storage_backend_serialized.cpp
index 929f4d5..fa8fe4e 100644 (file)
@@ -24,6 +24,7 @@
 #include <cerrno>
 #include <fcntl.h>
 #include <map>
+#include <string>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -43,6 +44,85 @@ typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
 template <typename T>
 struct type_helper;
 
+namespace {
+
+inline boost::string_ref s(const flatbuffers::String *str) {
+       return boost::string_ref(str->c_str(), str->size());
+}
+
+template <typename T, typename I>
+bool match(const T &match, const I *i) {
+       return match.match(makeMessageType(i->type()),
+                                          s(i->interface()),
+                                          s(i->path()),
+                                          s(i->member()),
+                                          s(i->name()),
+                                          i->is_name_prefix(),
+                                          makeDecision(i->decision()->decision()));
+}
+
+template <> bool match(const ldp_xml_parser::MatchItemAccess &match, const FB::ItemAccess *item) {
+       return match.match(makeBusAccessType(item->type()), item->uid(), item->gid());
+}
+
+template <typename T, typename P = typename type_helper<T>::policy_type>
+ldp_xml_parser::DecisionItem getDecisionItem(const T &item, const P *policy) {
+       const auto *v = policy->items();
+       for (auto it = v->rbegin(); it != v->rend(); ++it) {
+               if (match(item, *it))
+                       return makeDecisionItem((*it)->decision());
+       }
+       return ldp_xml_parser::Decision::ANY;
+}
+
+const DecisionItem *getDecisionItemFromTree(const FB::PolicyOwnNode *node,
+                                                                                       tokenizer &tokens,
+                                                                                       tokenizer::iterator &iterator) {
+       if (iterator == tokens.end()) {
+               if (node->decision_item()->decision() != Decision_ANY)
+                       return node->decision_item();
+               else
+                       return node->prefix_decision_item();
+       }
+
+       auto child = node->children()->LookupByKey(iterator->c_str());
+       if (nullptr == child)
+               return node->prefix_decision_item();
+
+       ++iterator;
+       const DecisionItem *child_decision = getDecisionItemFromTree(child, tokens, iterator);
+       if (child_decision->decision() == Decision_ANY)
+               return node->prefix_decision_item();
+
+       return child_decision;
+}
+
+template <> ldp_xml_parser::DecisionItem getDecisionItem(const ldp_xml_parser::MatchItemOwn &item,
+                                                                                                                const PolicyOwn *policy) {
+       if (item.getName().length() == 0)
+               return ldp_xml_parser::Decision::DENY;
+
+       boost::char_separator<char> separator(".");
+       tokenizer tokens(item.getName(), separator);
+
+       auto node = policy->tree();
+       if (nullptr == node)
+               return ldp_xml_parser::Decision::ANY;
+
+       auto iterator = tokens.begin();
+
+       return makeDecisionItem(getDecisionItemFromTree(node, tokens, iterator));
+}
+
+template <typename T, typename P = typename type_helper<T>::policy_type>
+ldp_xml_parser::DecisionItem getDecisionItemMaybeNull(const T &item, const P *policyPair) {
+       if (nullptr == policyPair)
+               return ldp_xml_parser::Decision::ANY;
+       return getDecisionItem(item, policyPair->policy());
+}
+
+} // anonymous namespace
+
 class StorageBackendSerialized::StorageBackendSerializedImpl {
        int fd{-1};
        uint8_t *mem{static_cast<decltype(mem)>(MAP_FAILED)};
@@ -54,27 +134,13 @@ class StorageBackendSerialized::StorageBackendSerializedImpl {
        void releaseMMap();
        void releaseFD();
 
-       typedef std::pair<const ItemSend *, unsigned> ItemWithScore;    // a pair: Item, index of Item
-       typedef std::vector<ItemWithScore> ItemsWithScore;                              // items
-       typedef std::pair<unsigned, ItemsWithScore> HighestScoreWithItems;      // value for index map: highest index for items, items
-       typedef std::map<boost::string_ref, HighestScoreWithItems> MapIndex;
-       typedef std::vector<ItemWithScore> SendPrefixIndex;
-
-       MapIndex sendIndex; // context default
-       SendPrefixIndex sendPrefixIndex; // context default prefix rules
-       std::map<uid_t, MapIndex> userSendIndex;
-       std::map<uid_t, SendPrefixIndex> userSendPrefixIndex;
-
 public:
        bool init(const char *filename, bool verify);
        bool init(const FB::File *f);
        bool initFromXML(const char *config_name);
        void release();
 
-       void createSendIndex();
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, const MapIndex &index, const SendPrefixIndex &prefixIndex);
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item);
-       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, uid_t uid);
+       ldp_xml_parser::DecisionItem getDecisionFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy);
 
        void printContent(const bool xml_format = false) const;
 
@@ -82,106 +148,73 @@ public:
        const M *getPolicySet();
 };
 
-inline boost::string_ref s(const flatbuffers::String *str) {
-       return boost::string_ref(str->c_str(), str->size());
-}
-
-template <typename T, typename I>
-bool match(const T &match, const I *i) {
-       return match.match(makeMessageType(i->type()),
-                                          s(i->interface()),
-                                          s(i->path()),
-                                          s(i->member()),
-                                          s(i->name()),
-                                          i->is_name_prefix(),
-                                          makeDecision(i->decision()->decision()));
-}
-
 ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item,
-               const MapIndex &index, const SendPrefixIndex &prefixIndex) {
-       ldp_xml_parser::DecisionItem decision(ldp_xml_parser::Decision::ANY);
+               const FB::PolicySend *policy) {
+
+       const auto *index = policy->index();
+
+       if (!index || index->size() == 0)           // this indicates version earlier than LDP2
+               return getDecisionItem(item, policy);   // make it old way for old databases
+
+       std::pair<const ItemSend*, uint32_t> currentBest(nullptr, 0);
+
+       auto updateCurrentBest = [&currentBest, &item, &policy](const flatbuffers::Vector<uint32_t> *vec) {
+               // look from the back, the rule is the same as for the full database
+               // we now only check among less elements, because the database is indexed to small lists
+               // item_scores are in increasing order in the index, and they serve also as ids of the policy rules
+               for (auto item_score_it = vec->rbegin(); item_score_it != vec->rend(); item_score_it++) {
+                       const auto *fb_item = policy->items()->Get(*item_score_it - 1); // rules are indexed/scored from 1
+                       if (*item_score_it > currentBest.second && match(item, fb_item)) {
+                               currentBest.first = fb_item;
+                               currentBest.second = *item_score_it;
+                               return;
+                       } else if (*item_score_it <= currentBest.second) {
+                               // there is no need to look further as we can't improve the score anymore
+                               return;
+                       }
+               }
+       };
 
-       ItemWithScore currentBest(nullptr, 0);
+       auto searchAndUpdateCurrentBest = [&currentBest, &index, &updateCurrentBest](boost::string_ref name_ref) {
+               // we need to create C-string for flatbuffers lookups
+               // boost::string_ref gives us correct start, but possibly NUL-terminated in a wrong place, as it does not modify
+               // input string and keeps only the length
+               std::string name(name_ref.data(), name_ref.size());
 
-       auto updateCurrentBest = [&currentBest, &item, &index](boost::string_ref name) {
                // check if there are any rules for the name
-               auto fit = index.find(name);
-               if (fit == index.end())
+               const auto *fit = index->LookupByKey(name.c_str());
+               if (!fit)
                        return;
 
                // check if there's any chance to get better score
-               // fit->second.first is the highest score from vector fit->second.second
-               if (fit->second.first <= currentBest.second)
+               if (fit->best_score() <= currentBest.second)
                        return;
 
                // look for better score
-               for (const auto &it: fit->second.second) {
-                       if (it.second > currentBest.second && match(item, it.first))
-                               currentBest = it;
-               }
+               updateCurrentBest(fit->item_refs());
        };
 
+       const auto *prefixIndex = policy->prefix_index();
+       assert(prefixIndex);
+
        // iterate over names
        for (const auto &name: item.getNames()) {
                // find and check the no-prefix rules
-               updateCurrentBest(name);
+               searchAndUpdateCurrentBest(name);
 
                // check the prefix rules
-               for (const auto &prefixItem: prefixIndex) {
-                       if (prefixItem.second > currentBest.second && match(item, prefixItem.first))
-                               currentBest = prefixItem;
-               }
+               updateCurrentBest(prefixIndex);
        }
 
        // check no-name rules
-       updateCurrentBest("");
+       searchAndUpdateCurrentBest("");
 
+       // if a matching rule was found, return the decision
        if (currentBest.first)
-               decision = makeDecisionItem(currentBest.first->decision());
-
-       return decision;
-}
-
-ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item) {
-       return getDecisionFromSendIndex(item, sendIndex, sendPrefixIndex);
-}
-
-ldp_xml_parser::DecisionItem StorageBackendSerialized::StorageBackendSerializedImpl::getDecisionFromSendIndex(const MatchItemSend &item, uid_t uid) {
-       return getDecisionFromSendIndex(item, userSendIndex[uid], userSendPrefixIndex[uid]);
-}
-
-void StorageBackendSerialized::StorageBackendSerializedImpl::createSendIndex() {
-       // helper for adding items to indexes
-       auto add = [](MapIndex &index, SendPrefixIndex &prefixIndex, boost::string_ref key, ItemWithScore value) {
-               if (value.first->is_name_prefix()) {
-                       prefixIndex.push_back(value);
-               } else {
-                       index[key].second.push_back(value);
-                       // we insert items in increasing score order, so we just update the highest score on each add
-                       index[key].first = value.second;
-               }
-       };
-
-       // context default index
-       const auto *policy = file->m_send_set()->context_default();
-       unsigned cnt = 1;
+               return makeDecisionItem(currentBest.first->decision());
 
-       const auto *v = policy->items();
-       for (auto it = v->begin(); it != v->end(); ++it)
-               add(sendIndex, sendPrefixIndex,
-                               boost::string_ref(it->name()->c_str(), it->name()->size()),
-                               ItemWithScore(*it, cnt++));
-
-       // users index
-       for (const auto &uidPolicy: *file->m_send_set()->user()) {
-               cnt = 1;
-               for (const auto it: *uidPolicy->policy()->items()) {
-                       add(userSendIndex[uidPolicy->id()],
-                                       userSendPrefixIndex[uidPolicy->id()],
-                                       boost::string_ref(it->name()->c_str(), it->name()->size()),
-                                       ItemWithScore(it, cnt++));
-               }
-       }
+       // or if no matching rule was not found, return the default decision
+       return ldp_xml_parser::DecisionItem(ldp_xml_parser::Decision::ANY);
 }
 
 void StorageBackendSerialized::StorageBackendSerializedImpl::releaseMMap() {
@@ -268,17 +301,13 @@ bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const char *fi
        mmapGuard.dismiss();
 
        file = GetFile(mem);
-       bool res = file != nullptr;
-       if (res)
-               createSendIndex();
-       return res;
+       return file != nullptr;
 }
 
 bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const FB::File *f) {
        assert(nullptr == file);
 
        file = f;
-       createSendIndex();
        return true;
 }
 
@@ -341,74 +370,19 @@ void StorageBackendSerialized::printContent(const bool xml_format) const {
        pimpl->printContent(xml_format);
 }
 
-template <> bool match(const ldp_xml_parser::MatchItemAccess &match, const FB::ItemAccess *item) {
-       return match.match(makeBusAccessType(item->type()), item->uid(), item->gid());
-}
-
-template <typename T, typename P = typename type_helper<T>::policy_type>
-ldp_xml_parser::DecisionItem getDecisionItem(const T &item, const P *policy) {
-       const auto *v = policy->items();
-       for (auto it = v->rbegin(); it != v->rend(); ++it) {
-               if (match(item, *it))
-                       return makeDecisionItem((*it)->decision());
-       }
-       return ldp_xml_parser::Decision::ANY;
-}
-
-const DecisionItem *getDecisionItemFromTree(const FB::PolicyOwnNode *node,
-                                                                                       tokenizer &tokens,
-                                                                                       tokenizer::iterator &iterator) {
-       if (iterator == tokens.end()) {
-               if (node->decision_item()->decision() != Decision_ANY)
-                       return node->decision_item();
-               else
-                       return node->prefix_decision_item();
-       }
-
-       auto child = node->children()->LookupByKey(iterator->c_str());
-       if (nullptr == child)
-               return node->prefix_decision_item();
-
-       ++iterator;
-       const DecisionItem *child_decision = getDecisionItemFromTree(child, tokens, iterator);
-       if (child_decision->decision() == Decision_ANY)
-               return node->prefix_decision_item();
-
-       return child_decision;
-}
-
-template <> ldp_xml_parser::DecisionItem getDecisionItem(const ldp_xml_parser::MatchItemOwn &item,
-                                                                                                                const PolicyOwn *policy) {
-       if (item.getName().length() == 0)
-               return ldp_xml_parser::Decision::DENY;
-
-       boost::char_separator<char> separator(".");
-       tokenizer tokens(item.getName(), separator);
-
-       auto node = policy->tree();
-       if (nullptr == node)
-               return ldp_xml_parser::Decision::ANY;
-
-       auto iterator = tokens.begin();
-
-       return makeDecisionItem(getDecisionItemFromTree(node, tokens, iterator));
-}
-
-template <typename T, typename P = typename type_helper<T>::policy_type>
-ldp_xml_parser::DecisionItem getDecisionItemMaybeNull(const T &item, const P *policyPair) {
-       if (nullptr == policyPair)
-               return ldp_xml_parser::Decision::ANY;
-       return getDecisionItem(item, policyPair->policy());
-}
-
 template <typename T>
 ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextMandatory(const T &item) const {
        return getDecisionItem(item, pimpl->getPolicySet<T>()->context_mandatory());
 }
 
 template <>
+ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextMandatory(const MatchItemSend &item) const {
+       return pimpl->getDecisionFromSendIndex(item, pimpl->getPolicySet<MatchItemSend>()->context_mandatory());
+}
+
+template <>
 ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextDefault(const MatchItemSend &item) const {
-       return pimpl->getDecisionFromSendIndex(item);
+       return pimpl->getDecisionFromSendIndex(item, pimpl->getPolicySet<MatchItemSend>()->context_default());
 }
 
 template <>
@@ -416,7 +390,7 @@ ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemUser(uid_t
        auto *policyPair = pimpl->getPolicySet<MatchItemSend>()->user()->LookupByKey(uid);
        if (nullptr == policyPair)
                return ldp_xml_parser::Decision::ANY;
-       return pimpl->getDecisionFromSendIndex(item, uid);
+       return pimpl->getDecisionFromSendIndex(item, policyPair->policy());
 }
 
 template <typename T>