2d0305fe49d15ce1d0a44439752c880b9742f59f
[platform/core/security/vist.git] / src / vist / policy / policy-storage.cpp
1 /*
2  *  Copyright (c) 2019-present 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
17 #include "policy-storage.hpp"
18
19 #include <vist/database/column.hpp>
20 #include <vist/database/statement.hpp>
21 #include <vist/exception.hpp>
22 #include <vist/logger.hpp>
23 #include <vist/query-builder.hpp>
24
25 #include <algorithm>
26 #include <fstream>
27
28 namespace {
29
30 const std::string SCRIPT_BASE = SCRIPT_INSTALL_DIR;
31 const std::string SCRIPT_CREATE_SCHEMA  = "create-schema";
32
33 } // anonymous namespace
34
35 namespace vist {
36 namespace policy {
37
38 PolicyStorage::PolicyStorage(const std::string& path) :
39         database(std::make_shared<database::Connection>(path))
40 {
41         database->exec("PRAGMA foreign_keys = ON;");
42         database->transactionBegin();
43         database->exec(getScript(SCRIPT_CREATE_SCHEMA));
44         database->transactionEnd();
45
46         sync();
47 }
48
49 void PolicyStorage::sync()
50 {
51         DEBUG(VIST) << "Sync policy storage to cache object.";
52         syncAdmin();
53         syncPolicyManaged();
54         syncPolicyDefinition();
55 }
56
57 void PolicyStorage::syncPolicyDefinition()
58 {
59         this->definitions.clear();
60         std::string query = schema::policyDefinition.selectAll();
61         database::Statement stmt(*database, query);
62
63         while (stmt.step()) {
64                 PolicyDefinition pd = { std::string(stmt.getColumn(0)), std::string(stmt.getColumn(1)) };
65                 DEBUG(VIST) << "Defined policy:" << pd.name;
66                 this->definitions.emplace(pd.name, std::move(pd));
67         }
68
69         DEBUG(VIST) << definitions.size() << "-policies synced.";
70 }
71
72 void PolicyStorage::syncAdmin()
73 {
74         this->admins.clear();
75         std::string query = schema::admin.selectAll();
76         database::Statement stmt(*database, query);
77
78         while (stmt.step()) {
79                 Admin admin = { std::string(stmt.getColumn(0)), stmt.getColumn(1).getInt() };
80                 this->admins.emplace(admin.name, std::move(admin));
81         }
82
83         DEBUG(VIST) << admins.size() << "-admins synced.";
84 }
85
86 void PolicyStorage::syncPolicyManaged()
87 {
88         this->managedPolicies.clear();
89         std::string query = schema::policyManaged.selectAll();
90         database::Statement stmt(*database, query);
91
92         while (stmt.step()) {
93                 PolicyManaged pa;
94                 pa.admin = std::string(stmt.getColumn(0));
95                 pa.policy = std::string(stmt.getColumn(1));
96                 pa.value = std::string(stmt.getColumn(2));
97                 this->managedPolicies.emplace(pa.policy, std::move(pa));
98         }
99
100         DEBUG(VIST) << managedPolicies.size() << "-managed-policies synced.";
101 }
102
103 std::string PolicyStorage::getScript(const std::string& name)
104 {
105         std::string path = SCRIPT_BASE + "/" + name + ".sql";
106         std::ifstream is(path);
107         if (is.fail())
108                 THROW(ErrCode::LogicError) << "Failed to open script: " << path;
109
110         std::istreambuf_iterator<char> begin(is), end;
111         auto content = std::string(begin, end);
112         if (content.empty())
113                 THROW(ErrCode::LogicError) << "Failed to read script: " << path;
114
115         return content;
116 }
117
118 void PolicyStorage::define(const std::string& policy, const PolicyValue& ivalue)
119 {
120         if (this->definitions.find(policy) != this->definitions.end()) {
121                 DEBUG(VIST) << "Policy is already defined: " << policy;
122                 return;
123         }
124
125         PolicyDefinition pd = { policy, ivalue.dump() };
126
127         std::string query = schema::PolicyDefinitionTable.insert(PolicyDefinition::Name,
128                                                                                                                          PolicyDefinition::Ivalue);
129         database::Statement stmt(*database, query);
130         stmt.bind(1, pd.name);
131         stmt.bind(2, pd.ivalue);
132         if (!stmt.exec())
133                 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
134
135         INFO(VIST) << "Policy defined >> name: " << pd.name << ", ivalue: " << pd.ivalue;
136         this->definitions.emplace(pd.name, std::move(pd));
137 }
138
139 void PolicyStorage::enroll(const std::string& name)
140 {
141         INFO(VIST) << "Enroll admin: " << name;
142         if (this->admins.find(name) != this->admins.end()) {
143                 WARN(VIST) << "Admin is already enrolled.: " << name;
144                 return;
145         }
146
147         /// Make admin deactivated as default.
148         Admin admin = {name , 0};
149
150         std::string query = schema::AdminTable.insert(Admin::Name, Admin::Activated);
151         database::Statement stmt(*database, query);
152         stmt.bind(1, admin.name);
153         stmt.bind(2, admin.activated);
154         if (!stmt.exec())
155                 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
156
157         this->admins.emplace(admin.name, std::move(admin));
158
159         /// PolicyManaged is triggered by enrolling admin.
160         syncPolicyManaged();
161
162         int count = this->managedPolicies.size() / this->admins.size();
163         INFO(VIST) << "Admin[" << name << "] manages "
164                            << std::to_string(count) << "-policies.";
165 }
166
167 void PolicyStorage::disenroll(const std::string& name)
168 {
169         if (name == DEFAULT_ADMIN_PATH)
170                 THROW(ErrCode::RuntimeError) << "Cannot disenroll default admin.";
171
172         INFO(VIST) << "Disenroll admin: " << name;
173         if (this->admins.find(name) == this->admins.end()) {
174                 ERROR(VIST) << "Not exist admin: " << name;
175                 return;
176         } else {
177                 this->admins.erase(name);
178         }
179
180         std::string query = schema::admin.remove().where(expr(&Admin::name) == name);
181         database::Statement stmt(*database, query);
182         stmt.bind(1, name);
183         if (!stmt.exec())
184                 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
185
186         /// TODO: add TC
187         this->syncPolicyManaged();
188 }
189
190 void PolicyStorage::activate(const std::string& admin, bool state)
191 {
192         if (this->admins.find(admin) == this->admins.end())
193                 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
194
195         DEBUG(VIST) << "Activate admin: " << admin;
196         /// Admin::Activated
197         std::string query = schema::AdminTable.update(Admin::Activated)
198                                                                                   .where(expr(&Admin::name) == admin);
199         database::Statement stmt(*this->database, query);
200         stmt.bind(1, static_cast<int>(state));
201         stmt.bind(2, admin);
202         if (!stmt.exec())
203                 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
204
205         this->admins[admin].activated = state;
206         INFO(VIST) << "Admin[" << admin << "]'s activated value is set: " << state; 
207 }
208
209 bool PolicyStorage::isActivated(const std::string& admin)
210 {
211         if (this->admins.find(admin) == this->admins.end())
212                 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
213
214         return this->admins[admin].activated;
215 }
216
217 bool PolicyStorage::isActivated()
218 {
219         for (const auto& admin : this->admins)
220                 if (admin.second.activated)
221                         return true;
222
223         return false;
224 }
225
226 void PolicyStorage::update(const std::string& admin,
227                                                    const std::string& policy,
228                                                    const PolicyValue& value)
229 {
230         DEBUG(VIST) << "Policy-update is called by admin: " << admin
231                                 << ", about: " << policy << ", value: " << value.dump();
232
233         if (this->admins.find(admin) == this->admins.end())
234                 THROW(ErrCode::LogicError) << "Not exist admin: " << admin;
235
236         if (this->definitions.find(policy) == this->definitions.end())
237                 THROW(ErrCode::LogicError) << "Not exist policy: " << policy;
238
239         std::string query = schema::PolicyManagedTable.update(PolicyManaged::Value)
240                                                                                                   .where(expr(&PolicyManaged::admin) == admin &&
241                                                                                                         expr(&PolicyManaged::policy) == policy);
242         database::Statement stmt(*this->database, query);
243         stmt.bind(1, value.dump());
244         stmt.bind(2, admin);
245         stmt.bind(3, policy);
246         if (!stmt.exec())
247                 THROW(ErrCode::RuntimeError) << stmt.getErrorMessage();
248
249         /// TODO: Fix to sync without db i/o
250         this->syncPolicyManaged();
251 }
252
253 PolicyValue PolicyStorage::strictest(const std::shared_ptr<PolicyModel>& policy)
254 {
255         if (this->definitions.find(policy->getName()) == this->definitions.end())
256                 THROW(ErrCode::LogicError) << "Not exist policy: " << policy->getName();
257
258         if (this->managedPolicies.size() == 0) {
259                 INFO(VIST) << "There is no enrolled admin. Return policy initial value.";
260                 return policy->getInitial();
261         }
262
263         std::shared_ptr<PolicyValue> strictestPtr = nullptr;
264         auto range = managedPolicies.equal_range(policy->getName());
265         for (auto iter = range.first; iter != range.second; iter++) {
266                 DEBUG(VIST) << "Admin: " << iter->second.admin << ", "
267                                         << "Policy: " << iter->second.policy  << ", "
268                                         << "Value: " << iter->second.value;
269
270                 if (strictestPtr == nullptr) {
271                         strictestPtr = std::make_shared<PolicyValue>(iter->second.value, true);
272                 } else {
273                         if (policy->compare(*strictestPtr, PolicyValue(iter->second.value, true)) > 0)
274                                 strictestPtr.reset(new PolicyValue(iter->second.value, true));
275                 }
276         }
277
278         if (strictestPtr == nullptr)
279                 THROW(ErrCode::RuntimeError) << "Not exist managed policy: " << policy;
280
281         DEBUG(VIST) << "The strictest value of [" << policy->getName()
282                                 << "] is " << strictestPtr->dump();
283
284         return std::move(*strictestPtr);
285 }
286
287 std::unordered_map<std::string, int> PolicyStorage::getAdmins() const noexcept
288 {
289         std::unordered_map<std::string, int> ret;
290         for (const auto& admin : this->admins)
291                 ret[admin.second.name] = admin.second.activated;
292
293         return ret;
294 }
295
296 } // namespace policy
297 } // namespace vist