serialization: use new interface for operations
[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 "serialized_convert.hpp"
18 #include "storage_backend_flatbuffers.hpp"
19 #include "tslog.hpp"
20 #include <boost/tokenizer.hpp>
21 #include <string>
22
23 using namespace FB;
24 using ldp_xml_parser::MatchItemSend;
25
26 namespace ldp_serialized {
27
28 namespace {
29
30 const unsigned int FB_ID_OFFSET = 4;
31 const unsigned int FB_ID_SIZE = 4;
32
33 } // anonymous namespace
34
35 template <typename T>
36 struct type_helper;
37
38 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::makeDecisionItem(const DecisionItem *item) const {
39         return ldp_xml_parser::DecisionItem(makeDecision(decisionItemGetDecision(item)),
40                                                          stringGetCStr(decisionItemGetPrivilege(item)));
41 }
42
43 boost::string_ref StorageBackendFlatbuffers::toStringRef(const flatbuffers::String *str) const {
44         return boost::string_ref(stringGetCStr(str), stringGetSize(str));
45 }
46
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))));
56 }
57
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));
60 }
61
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));
69         }
70         return ldp_xml_parser::Decision::ANY;
71 }
72
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);
79                 else
80                         return ownNodeGetPrefixDecisionItem(node);
81         }
82
83         auto children = ownNodeGetChildren(node);
84
85         if (containerEmpty(children))
86                 return ownNodeGetPrefixDecisionItem(node);
87
88         auto child = containerLookupByKey(children, iterator->c_str());
89         if (!child.first)
90                 return ownNodeGetPrefixDecisionItem(node);
91
92         ++iterator;
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);
96
97         return child_decision;
98 }
99
100 template <>
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;
105
106         boost::char_separator<char> separator(".");
107         tokenizer tokens(item.getName(), separator);
108
109         auto iterator = tokens.begin();
110
111         return makeDecisionItem(getDecisionItemFromTree(policyGetTree(policy), tokens.end(), iterator));
112 }
113
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;
118
119         auto elem = containerLookupByKey(map, id);
120         if (!elem.first)
121                 return ldp_xml_parser::Decision::ANY;
122         return getDecisionItem(item, setUserGroupGetPolicy(elem.second));
123 }
124
125 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemFromSendIndex(const MatchItemSend &item, const FB::PolicySend *policy) const {
126
127         if (!policyHasIndex(policy))
128                 return getDecisionItem(item, policy);   // make it old way for old databases
129
130         auto index = policyGetIndex(policy);
131
132         uint32_t currentBest = 0;
133
134         auto updateCurrentBest = [&currentBest, &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);
140                      item_score_it++) {
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;
145                                 return;
146                         } else if (*item_score_it <= currentBest) {
147                                 // there is no need to look further as we can't improve the score anymore
148                                 return;
149                         }
150                 }
151         };
152
153         auto searchAndUpdateCurrentBest = [&currentBest, &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());
158
159                 if (containerEmpty(index))
160                         return;
161
162                 // check if there are any rules for the name
163                 auto fit = containerLookupByKey(index, name.c_str());
164                 if (!fit.first)
165                         return;
166
167                 // check if there's any chance to get better score
168                 if (policyIndexGetBestScore(fit.second) <= currentBest)
169                         return;
170
171                 // look for better score
172                 updateCurrentBest(policyIndexGetItemRefs(fit.second));
173         };
174
175         auto prefixIndex = policyGetPrefixIndex(policy);
176
177         // iterate over names
178         for (const auto &name: item.getNames()) {
179                 // find and check the no-prefix rules
180                 searchAndUpdateCurrentBest(name);
181
182                 // check the prefix rules
183                 updateCurrentBest(prefixIndex);
184         }
185
186         // check no-name rules
187         searchAndUpdateCurrentBest("");
188
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));
193         }
194
195         // or if no matching rule was not found, return the default decision
196         return ldp_xml_parser::Decision::ANY;
197 }
198
199 void StorageBackendFlatbuffers::release() {
200         file = nullptr;
201 }
202
203 bool StorageBackendFlatbuffers::initFromData(const uint8_t *mem, size_t size, bool verify) {
204         assert(nullptr == file);
205
206         if (verify) {
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);
211
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");
216                         } else {
217                                 tslog::log_error("verification of serialized data: failed\n");
218                                 return false;
219                         }
220                 }
221         }
222
223         file = GetFile(mem);
224         return file != nullptr;
225 }
226
227 /*************************************************/
228 #define TYPE_HELPER(T, t) \
229         template <> \
230         struct type_helper<ldp_xml_parser::MatchItem##T> { \
231                 typedef FB::T##Set policy_set_type; \
232                 typedef FB::Policy##T policy_type; \
233         }; \
234         template <> \
235         auto StorageBackendFlatbuffers::getPolicySet<ldp_xml_parser::MatchItem##T>() const { \
236                 assert(file); \
237                 return fileGet##T##Set(getFile()); \
238         }
239
240 TYPE_HELPER(Own, own)
241 TYPE_HELPER(Send, send)
242 TYPE_HELPER(Receive, receive)
243 TYPE_HELPER(Access, access)
244
245 template <>
246 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const MatchItemSend &item) const {
247         return getDecisionItemFromSendIndex(item, setGetContextMandatory(getPolicySet<MatchItemSend>()));
248 }
249
250 template <>
251 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const MatchItemSend &item) const {
252         return getDecisionItemFromSendIndex(item, setGetContextDefault(getPolicySet<MatchItemSend>()));
253 }
254
255 template <>
256 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemUser(uid_t uid, const MatchItemSend &item) const {
257         auto map = setGetUser(getPolicySet<MatchItemSend>());
258
259         if (containerEmpty(map))
260                 return ldp_xml_parser::Decision::ANY;
261
262         auto elem = containerLookupByKey(map, uid);
263         if (!elem.first)
264                 return ldp_xml_parser::Decision::ANY;
265         return getDecisionItemFromSendIndex(item, setUserGroupGetPolicy(elem.second));
266 }
267
268 template <typename T>
269 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextMandatory(const T &item) const {
270         return getDecisionItem(item, setGetContextMandatory(getPolicySet<T>()));
271 }
272
273 template <typename T>
274 ldp_xml_parser::DecisionItem StorageBackendFlatbuffers::getDecisionItemContextDefault(const T &item) const {
275         return getDecisionItem(item, setGetContextDefault(getPolicySet<T>()));
276 }
277
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);
281 }
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);
285 }
286
287 template <typename T>
288 bool StorageBackendFlatbuffers::existsPolicyForGroup(gid_t gid) const {
289         auto map = setGetGroup(getPolicySet<T>());
290
291         if (containerEmpty(map))
292                 return false;
293
294         return containerLookupByKey(map, gid).first;
295 }
296
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;
300
301 T_INSTANTIATION(Own)
302 T_INSTANTIATION(Send)
303 T_INSTANTIATION(Receive)
304 T_INSTANTIATION(Access)
305
306 #undef T_INSTANTIATION
307
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;
312
313 T_INSTANTIATION2(Own)
314 T_INSTANTIATION2(Send)
315 T_INSTANTIATION2(Receive)
316
317 #undef T_INSTANTIATION2
318
319 StorageBackendFlatbuffers::StorageBackendFlatbuffers() {}
320 StorageBackendFlatbuffers::~StorageBackendFlatbuffers() {}
321
322 }