2 * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 #include "include/fb_generated.h"
17 #include "print_content.hpp"
18 #include "serialized_convert.hpp"
19 #include "storage_backend_flatbuffers.hpp"
21 #include <boost/tokenizer.hpp>
25 using ldp_xml_parser::MatchItemSend;
27 namespace ldp_serialized {
32 boost::string_ref StorageBackendFlatbuffers::toStringRef(const flatbuffers::String *str) const {
33 return boost::string_ref(str->c_str(), str->size());
36 template <typename T, typename I>
37 bool StorageBackendFlatbuffers::match(const T &match, const I *i) const {
38 return match.match(makeMessageType(i->type()),
39 toStringRef(i->interface()),
40 toStringRef(i->path()),
41 toStringRef(i->member()),
42 toStringRef(i->name()),
44 makeDecision(i->decision()->decision()));
47 bool StorageBackendFlatbuffers::match(const ldp_xml_parser::MatchItemAccess &match, const FB::ItemAccess *item) const {
48 return match.match(makeBusAccessType(item->type()), item->uid(), item->gid());
51 template <typename T, typename P = typename type_helper<T>::policy_type>
52 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItem(const T &item, const P *policy) const {
53 const auto *v = policy->items();
54 for (auto it = v->rbegin(); it != v->rend(); ++it) {
56 return makeDecisionItem((*it)->decision());
58 return ldp_xml_parser::Decision::ANY;
61 auto StorageBackendFlatbuffers::getDecisionItemFromTree(const FB::PolicyOwnNode *node,
62 const tokenizer::iterator &tokens_end,
63 tokenizer::iterator &iterator) const {
64 if (iterator == tokens_end) {
65 if (node->decision_item()->decision() != Decision_ANY)
66 return node->decision_item();
68 return node->prefix_decision_item();
71 auto child = node->children()->LookupByKey(iterator->c_str());
73 return node->prefix_decision_item();
76 const DecisionItem *child_decision = getDecisionItemFromTree(child, tokens_end, iterator);
77 if (child_decision->decision() == Decision_ANY)
78 return node->prefix_decision_item();
80 return child_decision;
84 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItem(const ldp_xml_parser::MatchItemOwn &item,
85 const PolicyOwn *policy) const {
86 if (item.getName().length() == 0)
87 return ldp_xml_parser::Decision::DENY;
89 boost::char_separator<char> separator(".");
90 tokenizer tokens(item.getName(), separator);
92 auto node = policy->tree();
94 return ldp_xml_parser::Decision::ANY;
96 auto iterator = tokens.begin();
98 return makeDecisionItem(getDecisionItemFromTree(node, tokens.end(), iterator));
101 template <typename T, typename P = typename type_helper<T>::policy_type>
102 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemMaybeNull(const T &item, const P *policyPair) const {
103 if (nullptr == policyPair)
104 return ldp_xml_parser::Decision::ANY;
105 return getDecisionItem(item, policyPair->policy());
108 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy) const {
110 const auto *index = policy->index();
112 if (!index || index->size() == 0) // this indicates version earlier than LDP2
113 return getDecisionItem(item, policy); // make it old way for old databases
115 std::pair<const ItemSend*, uint32_t> currentBest(nullptr, 0);
117 auto updateCurrentBest = [&](const flatbuffers::Vector<uint32_t> *vec) {
118 // look from the back, the rule is the same as for the full database
119 // we now only check among less elements, because the database is indexed to small lists
120 // item_scores are in increasing order in the index, and they serve also as ids of the policy rules
121 for (auto item_score_it = vec->rbegin(); item_score_it != vec->rend(); item_score_it++) {
122 const auto *fb_item = policy->items()->Get(*item_score_it - 1); // rules are indexed/scored from 1
123 if (*item_score_it > currentBest.second && match(item, fb_item)) {
124 currentBest.first = fb_item;
125 currentBest.second = *item_score_it;
127 } else if (*item_score_it <= currentBest.second) {
128 // there is no need to look further as we can't improve the score anymore
134 auto searchAndUpdateCurrentBest = [&](boost::string_ref name_ref) {
135 // we need to create C-string for flatbuffers lookups
136 // boost::string_ref gives us correct start, but possibly NUL-terminated in a wrong place, as it does not modify
137 // input string and keeps only the length
138 std::string name(name_ref.data(), name_ref.size());
140 // check if there are any rules for the name
141 const auto *fit = index->LookupByKey(name.c_str());
145 // check if there's any chance to get better score
146 if (fit->best_score() <= currentBest.second)
149 // look for better score
150 updateCurrentBest(fit->item_refs());
153 const auto *prefixIndex = policy->prefix_index();
156 // iterate over names
157 for (const auto &name: item.getNames()) {
158 // find and check the no-prefix rules
159 searchAndUpdateCurrentBest(name);
161 // check the prefix rules
162 updateCurrentBest(prefixIndex);
165 // check no-name rules
166 searchAndUpdateCurrentBest("");
168 // if a matching rule was found, return the decision
169 if (currentBest.first)
170 return makeDecisionItem(currentBest.first->decision());
172 // or if no matching rule was not found, return the default decision
173 return ldp_xml_parser::DecisionItem(ldp_xml_parser::Decision::ANY);
176 void StorageBackendFlatbuffers::release() {
180 bool StorageBackendFlatbuffers::initFromData(const uint8_t *mem, size_t size, bool verify) {
181 assert(nullptr == file);
184 auto verifier = flatbuffers::Verifier(mem, size);
185 if (!FB::VerifyFileBuffer(verifier) || !FB::FileBufferHasIdentifier(mem)) {
186 char fid[FB::FB_ID_SIZE + 1] = {0, };
187 strncpy(fid, (const char *)(mem + FB::FB_ID_OFFSET), FB::FB_ID_SIZE);
189 if (strcmp(fid, "LDP1") == 0) {
190 tslog::log_error("verification of serialized data: not available\n");
191 tslog::log_error("header ID : ", FB::FileIdentifier(), "\n");
192 tslog::log_error("serialized data ID : ", fid, "\n");
194 tslog::log_error("verification of serialized data: failed\n");
201 return file != nullptr;
204 void StorageBackendFlatbuffers::printContent(const bool xml_format) const {
205 print_content::use_xml_format(xml_format);
209 /*************************************************/
210 #define TYPE_HELPER(T, t) \
212 struct type_helper<ldp_xml_parser::MatchItem##T> { \
213 typedef FB::T##Set policy_set_type; \
214 typedef FB::Policy##T policy_type; \
217 auto StorageBackendFlatbuffers::getPolicySet<ldp_xml_parser::MatchItem##T>() const { \
219 return file->m_##t##_set(); \
222 TYPE_HELPER(Own, own)
223 TYPE_HELPER(Send, send)
224 TYPE_HELPER(Receive, receive)
225 TYPE_HELPER(Access, access)
228 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const MatchItemSend &item) const {
229 return getDecisionItemFromSendIndex(item, getPolicySet<MatchItemSend>()->context_mandatory());
233 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const MatchItemSend &item) const {
234 return getDecisionItemFromSendIndex(item, getPolicySet<MatchItemSend>()->context_default());
238 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const MatchItemSend &item) const {
239 auto *policyPair = getPolicySet<MatchItemSend>()->user()->LookupByKey(uid);
240 if (nullptr == policyPair)
241 return ldp_xml_parser::Decision::ANY;
242 return getDecisionItemFromSendIndex(item, policyPair->policy());
245 template <typename T>
246 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const T &item) const {
247 return getDecisionItem(item, getPolicySet<T>()->context_mandatory());
250 template <typename T>
251 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const T &item) const {
252 return getDecisionItem(item, getPolicySet<T>()->context_default());
255 template <typename T>
256 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const T &item) const {
257 return getDecisionItemMaybeNull(item, getPolicySet<T>()->user()->LookupByKey(uid));
260 template <typename T>
261 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemGroup(gid_t gid, const T &item) const {
262 return getDecisionItemMaybeNull(item, getPolicySet<T>()->group()->LookupByKey(gid));
265 template <typename T>
266 bool StorageBackendFlatbuffers::existsPolicyForGroup(gid_t gid) const {
267 return getPolicySet<T>()->group()->LookupByKey(gid) != nullptr;
270 #define T_INSTANTIATION(T) \
271 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const ldp_xml_parser::MatchItem##T &item) const; \
272 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const ldp_xml_parser::MatchItem##T &item) const;
275 T_INSTANTIATION(Send)
276 T_INSTANTIATION(Receive)
277 T_INSTANTIATION(Access)
279 #undef T_INSTANTIATION
281 #define T_INSTANTIATION2(T) \
282 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const ldp_xml_parser::MatchItem##T &item) const; \
283 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemGroup(gid_t gid, const ldp_xml_parser::MatchItem##T &item) const; \
284 template bool StorageBackendFlatbuffers::existsPolicyForGroup<ldp_xml_parser::MatchItem##T>(gid_t) const;
286 T_INSTANTIATION2(Own)
287 T_INSTANTIATION2(Send)
288 T_INSTANTIATION2(Receive)
290 #undef T_INSTANTIATION2
292 StorageBackendFlatbuffers::StorageBackendFlatbuffers() {}
293 StorageBackendFlatbuffers::~StorageBackendFlatbuffers() {}