#include <boost/tokenizer.hpp>
#include <cerrno>
#include <fcntl.h>
+#include <map>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using namespace FB;
+using ldp_xml_parser::MatchItemSend;
namespace ldp_serialized {
// 1MB. Adjustable
#define MAX_SFILE_SIZE (1024 * 1024)
+typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
+
template <typename T>
struct type_helper;
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);
+
void printContent() const;
template <typename T, typename M = typename type_helper<T>::policy_set_type>
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);
+
+ ItemWithScore currentBest(nullptr, 0);
+
+ auto updateCurrentBest = [¤tBest, &item, &index](boost::string_ref name) {
+ // check if there are any rules for the name
+ auto fit = index.find(name);
+ if (fit == index.end())
+ 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)
+ return;
+
+ // look for better score
+ for (const auto &it: fit->second.second) {
+ if (it.second > currentBest.second && match(item, it.first))
+ currentBest = it;
+ }
+ };
+
+ // iterate over names
+ for (const auto &name: item.getNames()) {
+ // find and check the no-prefix rules
+ updateCurrentBest(name);
+
+ // check the prefix rules
+ for (const auto &prefixItem: prefixIndex) {
+ if (prefixItem.second > currentBest.second && match(item, prefixItem.first))
+ currentBest = prefixItem;
+ }
+ }
+
+ // check no-name rules
+ updateCurrentBest("");
+
+ 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;
+
+ 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++));
+ }
+ }
+}
+
void StorageBackendSerialized::StorageBackendSerializedImpl::releaseMMap() {
assert(MAP_FAILED != mem);
assert(0 != length);
mmapGuard.dismiss();
file = GetFile(mem);
- return file != nullptr;
+ bool res = file != nullptr;
+ if (res)
+ createSendIndex();
+ return res;
}
bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const FB::File *f) {
assert(nullptr == file);
file = f;
+ createSendIndex();
return true;
}
pimpl->printContent();
}
-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());
}
return ldp_xml_parser::Decision::ANY;
}
-typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
-
const DecisionItem *getDecisionItemFromTree(const FB::PolicyOwnNode *node,
tokenizer &tokens,
tokenizer::iterator &iterator) {
return getDecisionItem(item, pimpl->getPolicySet<T>()->context_mandatory());
}
+template <>
+ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextDefault(const MatchItemSend &item) const {
+ return pimpl->getDecisionFromSendIndex(item);
+}
+
+template <>
+ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemUser(uid_t uid, const MatchItemSend &item) const {
+ auto *policyPair = pimpl->getPolicySet<MatchItemSend>()->user()->LookupByKey(uid);
+ if (nullptr == policyPair)
+ return ldp_xml_parser::Decision::ANY;
+ return pimpl->getDecisionFromSendIndex(item, uid);
+}
+
template <typename T>
ldp_xml_parser::DecisionItem StorageBackendSerialized::getDecisionItemContextDefault(const T &item) const {
return getDecisionItem(item, pimpl->getPolicySet<T>()->context_default());