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 "serialized_convert.hpp"
18 #include "storage_backend_flatbuffers.hpp"
20 #include <boost/tokenizer.hpp>
24 using ldp_xml_parser::MatchItemSend;
26 namespace ldp_serialized {
30 const unsigned int FB_ID_OFFSET = 4;
31 const unsigned int FB_ID_SIZE = 4;
33 } // anonymous namespace
38 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::makeDecisionItem(const DecisionItem *item) const {
39 return ldp_xml_parser::DecisionItem(makeDecision(decisionItemGetDecision(item)),
40 stringGetCStr(decisionItemGetPrivilege(item)));
43 boost::string_ref StorageBackendFlatbuffers::toStringRef(const flatbuffers::String *str) const {
44 return boost::string_ref(stringGetCStr(str), stringGetSize(str));
47 template <typename T, typename I>
48 bool StorageBackendFlatbuffers::match(const T &match, const I *i) const {
49 return match.match(makeMessageType(itemSrGetMessageType(i)),
50 toStringRef(itemSrGetInterface(i)),
51 toStringRef(itemSrGetPath(i)),
52 toStringRef(itemSrGetMember(i)),
53 toStringRef(itemSrGetName(i)),
54 itemSrGetIsNamePrefix(i),
55 makeDecision(decisionItemGetDecision(itemGetDecisionItem(i))));
58 bool StorageBackendFlatbuffers::match(const ldp_xml_parser::MatchItemAccess &match, const FB::ItemAccess *item) const {
59 return match.match(makeBusAccessType(itemAccessGetType(item)), itemAccessGetUid(item), itemAccessGetGid(item));
62 template <typename T, typename P = typename type_helper<T>::policy_type>
63 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItem(const T &item, const P *policy) const {
64 const auto *v = policyGetItems(policy);
65 auto rend = containerGetReverseIteratorEnd(v);
66 for (auto rit = containerGetReverseIterator(v); rit != rend; ++rit) {
67 if (match(item, *rit))
68 return makeDecisionItem(itemGetDecisionItem(*rit));
70 return ldp_xml_parser::Decision::ANY;
73 auto StorageBackendFlatbuffers::getDecisionItemFromTree(const FB::PolicyOwnNode *node,
74 const tokenizer::iterator &tokens_end,
75 tokenizer::iterator &iterator) const {
76 if (iterator == tokens_end) {
77 if (makeDecision(decisionItemGetDecision(ownNodeGetDecisionItem(node))) != ldp_xml_parser::Decision::ANY)
78 return ownNodeGetDecisionItem(node);
80 return ownNodeGetPrefixDecisionItem(node);
83 auto children = ownNodeGetChildren(node);
85 if (containerEmpty(children))
86 return ownNodeGetPrefixDecisionItem(node);
88 auto child = containerLookupByKey(children, iterator->c_str());
90 return ownNodeGetPrefixDecisionItem(node);
93 auto child_decision = getDecisionItemFromTree(child.second, tokens_end, iterator);
94 if (makeDecision(decisionItemGetDecision(child_decision)) == ldp_xml_parser::Decision::ANY)
95 return ownNodeGetPrefixDecisionItem(node);
97 return child_decision;
101 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItem(const ldp_xml_parser::MatchItemOwn &item,
102 const PolicyOwn *policy) const {
103 if (item.getName().length() == 0)
104 return ldp_xml_parser::Decision::DENY;
106 boost::char_separator<char> separator(".");
107 tokenizer tokens(item.getName(), separator);
109 auto iterator = tokens.begin();
111 return makeDecisionItem(getDecisionItemFromTree(policyGetTree(policy), tokens.end(), iterator));
114 template <typename MatchItem, typename Map>
115 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItem(const MatchItem &item, const Map &map, id_t id) const {
116 if (containerEmpty(map))
117 return ldp_xml_parser::Decision::ANY;
119 auto elem = containerLookupByKey(map, id);
121 return ldp_xml_parser::Decision::ANY;
122 return getDecisionItem(item, setUserGroupGetPolicy(elem.second));
125 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy) const {
127 if (!policyHasIndex(policy))
128 return getDecisionItem(item, policy); // make it old way for old databases
130 auto index = policyGetIndex(policy);
132 uint32_t currentBest = 0;
134 auto updateCurrentBest = [¤tBest, &item, &policy, this](const auto &vec) {
135 // look from the back, the rule is the same as for the full database
136 // we now only check among less elements, because the database is indexed to small lists
137 // item_scores are in increasing order in the index, and they serve also as ids of the policy rules
138 for (auto item_score_it = containerGetReverseIterator(vec);
139 item_score_it != containerGetReverseIteratorEnd(vec);
141 auto db_items = policyGetItems(policy);
142 auto db_item = containerLookupByIndex(db_items, *item_score_it - 1); // rules are indexed/scored from 1
143 if (*item_score_it > currentBest && match(item, db_item)) {
144 currentBest = *item_score_it;
146 } else if (*item_score_it <= currentBest) {
147 // there is no need to look further as we can't improve the score anymore
153 auto searchAndUpdateCurrentBest = [¤tBest, &index, &updateCurrentBest, this](boost::string_ref name_ref) {
154 // we need to create C-string for flatbuffers lookups
155 // boost::string_ref gives us correct start, but possibly NUL-terminated in a wrong place, as it does not modify
156 // input string and keeps only the length
157 std::string name(name_ref.data(), name_ref.size());
159 if (containerEmpty(index))
162 // check if there are any rules for the name
163 auto fit = containerLookupByKey(index, name.c_str());
167 // check if there's any chance to get better score
168 if (policyIndexGetBestScore(fit.second) <= currentBest)
171 // look for better score
172 updateCurrentBest(policyIndexGetItemRefs(fit.second));
175 auto prefixIndex = policyGetPrefixIndex(policy);
177 // iterate over names
178 for (const auto &name: item.getNames()) {
179 // find and check the no-prefix rules
180 searchAndUpdateCurrentBest(name);
182 // check the prefix rules
183 updateCurrentBest(prefixIndex);
186 // check no-name rules
187 searchAndUpdateCurrentBest("");
189 // if a matching rule was found, return the decision
190 if (currentBest > 0) {
191 auto db_item = containerLookupByIndex(policyGetItems(policy), currentBest - 1);
192 return makeDecisionItem(itemGetDecisionItem(db_item));
195 // or if no matching rule was not found, return the default decision
196 return ldp_xml_parser::Decision::ANY;
199 void StorageBackendFlatbuffers::release() {
203 bool StorageBackendFlatbuffers::initFromData(const uint8_t *mem, size_t size, bool verify) {
204 assert(nullptr == file);
207 auto verifier = flatbuffers::Verifier(mem, size);
208 if (!FB::VerifyFileBuffer(verifier) || !FB::FileBufferHasIdentifier(mem)) {
209 char fid[FB_ID_SIZE + 1] = {0, };
210 strncpy(fid, (const char *)(mem + FB_ID_OFFSET), FB_ID_SIZE);
212 if (strcmp(fid, "LDP1") == 0) {
213 tslog::log_error("verification of serialized data: not available\n");
214 tslog::log_error("header ID : ", FB::FileIdentifier(), "\n");
215 tslog::log_error("serialized data ID : ", fid, "\n");
217 tslog::log_error("verification of serialized data: failed\n");
224 return file != nullptr;
227 /*************************************************/
228 #define TYPE_HELPER(T, t) \
230 struct type_helper<ldp_xml_parser::MatchItem##T> { \
231 typedef FB::T##Set policy_set_type; \
232 typedef FB::Policy##T policy_type; \
235 auto StorageBackendFlatbuffers::getPolicySet<ldp_xml_parser::MatchItem##T>() const { \
237 return fileGet##T##Set(getFile()); \
240 TYPE_HELPER(Own, own)
241 TYPE_HELPER(Send, send)
242 TYPE_HELPER(Receive, receive)
243 TYPE_HELPER(Access, access)
246 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const MatchItemSend &item) const {
247 return getDecisionItemFromSendIndex(item, setGetContextMandatory(getPolicySet<MatchItemSend>()));
251 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const MatchItemSend &item) const {
252 return getDecisionItemFromSendIndex(item, setGetContextDefault(getPolicySet<MatchItemSend>()));
256 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const MatchItemSend &item) const {
257 auto map = setGetUser(getPolicySet<MatchItemSend>());
259 if (containerEmpty(map))
260 return ldp_xml_parser::Decision::ANY;
262 auto elem = containerLookupByKey(map, uid);
264 return ldp_xml_parser::Decision::ANY;
265 return getDecisionItemFromSendIndex(item, setUserGroupGetPolicy(elem.second));
268 template <typename T>
269 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const T &item) const {
270 return getDecisionItem(item, setGetContextMandatory(getPolicySet<T>()));
273 template <typename T>
274 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const T &item) const {
275 return getDecisionItem(item, setGetContextDefault(getPolicySet<T>()));
278 template <typename T>
279 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const T &item) const {
280 return getDecisionItem(item, setGetUser(getPolicySet<T>()), uid);
282 template <typename T>
283 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemGroup(gid_t gid, const T &item) const {
284 return getDecisionItem(item, setGetGroup(getPolicySet<T>()), gid);
287 template <typename T>
288 bool StorageBackendFlatbuffers::existsPolicyForGroup(gid_t gid) const {
289 auto map = setGetGroup(getPolicySet<T>());
291 if (containerEmpty(map))
294 return containerLookupByKey(map, gid).first;
297 #define T_INSTANTIATION(T) \
298 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const ldp_xml_parser::MatchItem##T &item) const; \
299 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const ldp_xml_parser::MatchItem##T &item) const;
302 T_INSTANTIATION(Send)
303 T_INSTANTIATION(Receive)
304 T_INSTANTIATION(Access)
306 #undef T_INSTANTIATION
308 #define T_INSTANTIATION2(T) \
309 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const ldp_xml_parser::MatchItem##T &item) const; \
310 template ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemGroup(gid_t gid, const ldp_xml_parser::MatchItem##T &item) const; \
311 template bool StorageBackendFlatbuffers::existsPolicyForGroup<ldp_xml_parser::MatchItem##T>(gid_t) const;
313 T_INSTANTIATION2(Own)
314 T_INSTANTIATION2(Send)
315 T_INSTANTIATION2(Receive)
317 #undef T_INSTANTIATION2
319 StorageBackendFlatbuffers::StorageBackendFlatbuffers() {}
320 StorageBackendFlatbuffers::~StorageBackendFlatbuffers() {}