refactoring: move local functions to the class
[platform/core/system/libdbuspolicy.git] / src / internal / storage_backend_flatbuffers.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15 */
16 #include "include/fb_generated.h"
17 #include "print_content.hpp"
18 #include "serialized_convert.hpp"
19 #include "storage_backend_flatbuffers.hpp"
20 #include "tslog.hpp"
21 #include <boost/tokenizer.hpp>
22 #include <string>
23
24 using namespace FB;
25 using ldp_xml_parser::MatchItemSend;
26
27 namespace ldp_serialized {
28
29 template <typename T>
30 struct type_helper;
31
32 boost::string_ref StorageBackendFlatbuffers::toStringRef(const flatbuffers::String *str) const {
33         return boost::string_ref(str->c_str(), str->size());
34 }
35
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()),
43                                            i->is_name_prefix(),
44                                            makeDecision(i->decision()->decision()));
45 }
46
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());
49 }
50
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) {
55                 if (match(item, *it))
56                         return makeDecisionItem((*it)->decision());
57         }
58         return ldp_xml_parser::Decision::ANY;
59 }
60
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();
67                 else
68                         return node->prefix_decision_item();
69         }
70
71         auto child = node->children()->LookupByKey(iterator->c_str());
72         if (nullptr == child)
73                 return node->prefix_decision_item();
74
75         ++iterator;
76         const DecisionItem *child_decision = getDecisionItemFromTree(child, tokens_end, iterator);
77         if (child_decision->decision() == Decision_ANY)
78                 return node->prefix_decision_item();
79
80         return child_decision;
81 }
82
83 template <>
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;
88
89         boost::char_separator<char> separator(".");
90         tokenizer tokens(item.getName(), separator);
91
92         auto node = policy->tree();
93         if (nullptr == node)
94                 return ldp_xml_parser::Decision::ANY;
95
96         auto iterator = tokens.begin();
97
98         return makeDecisionItem(getDecisionItemFromTree(node, tokens.end(), iterator));
99 }
100
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());
106 }
107
108 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy) const {
109
110         const auto *index = policy->index();
111
112         if (!index || index->size() == 0)           // this indicates version earlier than LDP2
113                 return getDecisionItem(item, policy);   // make it old way for old databases
114
115         std::pair<const ItemSend*, uint32_t> currentBest(nullptr, 0);
116
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;
126                                 return;
127                         } else if (*item_score_it <= currentBest.second) {
128                                 // there is no need to look further as we can't improve the score anymore
129                                 return;
130                         }
131                 }
132         };
133
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());
139
140                 // check if there are any rules for the name
141                 const auto *fit = index->LookupByKey(name.c_str());
142                 if (!fit)
143                         return;
144
145                 // check if there's any chance to get better score
146                 if (fit->best_score() <= currentBest.second)
147                         return;
148
149                 // look for better score
150                 updateCurrentBest(fit->item_refs());
151         };
152
153         const auto *prefixIndex = policy->prefix_index();
154         assert(prefixIndex);
155
156         // iterate over names
157         for (const auto &name: item.getNames()) {
158                 // find and check the no-prefix rules
159                 searchAndUpdateCurrentBest(name);
160
161                 // check the prefix rules
162                 updateCurrentBest(prefixIndex);
163         }
164
165         // check no-name rules
166         searchAndUpdateCurrentBest("");
167
168         // if a matching rule was found, return the decision
169         if (currentBest.first)
170                 return makeDecisionItem(currentBest.first->decision());
171
172         // or if no matching rule was not found, return the default decision
173         return ldp_xml_parser::DecisionItem(ldp_xml_parser::Decision::ANY);
174 }
175
176 void StorageBackendFlatbuffers::release() {
177         file = nullptr;
178 }
179
180 bool StorageBackendFlatbuffers::initFromData(const uint8_t *mem, size_t size, bool verify) {
181         assert(nullptr == file);
182
183         if (verify) {
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);
188
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");
193                         } else {
194                                 tslog::log_error("verification of serialized data: failed\n");
195                                 return false;
196                         }
197                 }
198         }
199
200         file = GetFile(mem);
201         return file != nullptr;
202 }
203
204 void StorageBackendFlatbuffers::printContent(const bool xml_format) const {
205         print_content::use_xml_format(xml_format);
206         std::cerr << *file;
207 }
208
209 /*************************************************/
210 #define TYPE_HELPER(T, t) \
211         template <> \
212         struct type_helper<ldp_xml_parser::MatchItem##T> { \
213                 typedef FB::T##Set policy_set_type; \
214                 typedef FB::Policy##T policy_type; \
215         }; \
216         template <> \
217         auto StorageBackendFlatbuffers::getPolicySet<ldp_xml_parser::MatchItem##T>() const { \
218                 assert(file); \
219                 return file->m_##t##_set(); \
220         }
221
222 TYPE_HELPER(Own, own)
223 TYPE_HELPER(Send, send)
224 TYPE_HELPER(Receive, receive)
225 TYPE_HELPER(Access, access)
226
227 template <>
228 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const MatchItemSend &item) const {
229         return getDecisionItemFromSendIndex(item, getPolicySet<MatchItemSend>()->context_mandatory());
230 }
231
232 template <>
233 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const MatchItemSend &item) const {
234         return getDecisionItemFromSendIndex(item, getPolicySet<MatchItemSend>()->context_default());
235 }
236
237 template <>
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());
243 }
244
245 template <typename T>
246 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const T &item) const {
247         return getDecisionItem(item, getPolicySet<T>()->context_mandatory());
248 }
249
250 template <typename T>
251 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const T &item) const {
252         return getDecisionItem(item, getPolicySet<T>()->context_default());
253 }
254
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));
258 }
259
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));
263 }
264
265 template <typename T>
266 bool StorageBackendFlatbuffers::existsPolicyForGroup(gid_t gid) const {
267         return getPolicySet<T>()->group()->LookupByKey(gid) != nullptr;
268 }
269
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;
273
274 T_INSTANTIATION(Own)
275 T_INSTANTIATION(Send)
276 T_INSTANTIATION(Receive)
277 T_INSTANTIATION(Access)
278
279 #undef T_INSTANTIATION
280
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;
285
286 T_INSTANTIATION2(Own)
287 T_INSTANTIATION2(Send)
288 T_INSTANTIATION2(Receive)
289
290 #undef T_INSTANTIATION2
291
292 StorageBackendFlatbuffers::StorageBackendFlatbuffers() {}
293 StorageBackendFlatbuffers::~StorageBackendFlatbuffers() {}
294
295 }