2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Rafal Krypa <r.krypa@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
20 * @author Rafal Krypa <r.krypa@samsung.com>
21 * @brief Wrapper class for Cynara interface
27 #include <dpl/log/log.h>
29 namespace SecurityManager {
32 * Rules for apps and users are organized into set of buckets stored in Cynara.
33 * Bucket is set of rules (app, uid, privilege) -> (DENY, ALLOW, BUCKET, ...).
34 * |------------------------|
37 * |------------------------|
39 * |------------------------|
40 * | app1 uid1 priv1 DENY |
41 * | * uid2 priv2 DENY |
42 * | * * * Bucket:MAIN|
43 * |------------------------|
45 * For details about buckets see Cynara documentation.
47 * Security Manager currently defines 8 buckets:
48 * - PRIVACY_MANAGER - first bucket during search (which is actually default bucket
49 * with empty string as id). If user specifies his preference then required rule
51 * - MAIN - holds rules denied by manufacturer, redirects to MANIFESTS
52 * bucket and holds entries for each user pointing to User Type
54 * - MANIFESTS - stores rules needed by installed apps (from package
59 * - USER_TYPE_GUEST - they store privileges from templates for apropriate
60 * user type. ALLOW rules only.
61 * - ADMIN - stores custom rules introduced by device administrator.
62 * Ignored if no matching rule found.
64 * Below is basic layout of buckets:
66 * |------------------------|
70 * | * * * Bucket:MAIN| |------------------|
71 * |------------------------| | <<deny>> |
73 * ----------------- | | |
74 * | | |------------------|
76 * |------------------------| |
79 * |---------------| | | |-------------------|
80 * | <<deny>> |<--| * * * Bucket:MANIFESTS|---->| <<deny>> |
81 * | USER_TYPE_SYST| |------------------------| | USER_TYPE_NORMAL |
83 * |---------------| | | |-------------------|
86 * | |---------------| |---------------| |
87 * | | <<deny>> | | <<deny>> | |
88 * | |USER_TYPE_GUEST| |USER_TYPE_ADMIN| |
90 * | |---------------| |---------------| |
95 * | |------------------| |
96 * |-------------> | <<none>> | <---------------|
99 * |------------------|
102 CynaraAdmin::BucketsMap CynaraAdmin::Buckets =
104 { Bucket::PRIVACY_MANAGER, std::string(CYNARA_ADMIN_DEFAULT_BUCKET)},
105 { Bucket::MAIN, std::string("MAIN")},
106 { Bucket::USER_TYPE_ADMIN, std::string("USER_TYPE_ADMIN")},
107 { Bucket::USER_TYPE_NORMAL, std::string("USER_TYPE_NORMAL")},
108 { Bucket::USER_TYPE_GUEST, std::string("USER_TYPE_GUEST") },
109 { Bucket::USER_TYPE_SYSTEM, std::string("USER_TYPE_SYSTEM")},
110 { Bucket::ADMIN, std::string("ADMIN")},
111 { Bucket::MANIFESTS, std::string("MANIFESTS")},
115 CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user,
116 const std::string &privilege, Operation operation,
117 const std::string &bucket)
119 this->client = strdup(client.c_str());
120 this->user = strdup(user.c_str());
121 this->privilege = strdup(privilege.c_str());
122 this->bucket = strdup(bucket.c_str());
124 if (this->bucket == nullptr || this->client == nullptr ||
125 this->user == nullptr || this->privilege == nullptr) {
129 free(this->privilege);
130 ThrowMsg(CynaraException::OutOfMemory,
131 std::string("Error in CynaraAdminPolicy allocation."));
134 this->result = static_cast<int>(operation);
135 this->result_extra = nullptr;
138 CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user,
139 const std::string &privilege, const std::string &goToBucket,
140 const std::string &bucket)
142 this->bucket = strdup(bucket.c_str());
143 this->client = strdup(client.c_str());
144 this->user = strdup(user.c_str());
145 this->privilege = strdup(privilege.c_str());
146 this->result_extra = strdup(goToBucket.c_str());
147 this->result = CYNARA_ADMIN_BUCKET;
149 if (this->bucket == nullptr || this->client == nullptr ||
150 this->user == nullptr || this->privilege == nullptr ||
151 this->result_extra == nullptr) {
155 free(this->privilege);
156 free(this->result_extra);
157 ThrowMsg(CynaraException::OutOfMemory,
158 std::string("Error in CynaraAdminPolicy allocation."));
162 CynaraAdminPolicy::CynaraAdminPolicy(CynaraAdminPolicy &&that)
164 bucket = that.bucket;
165 client = that.client;
167 privilege = that.privilege;
168 result_extra = that.result_extra;
169 result = that.result;
171 that.bucket = nullptr;
172 that.client = nullptr;
174 that.privilege = nullptr;
175 that.result_extra = nullptr;
178 CynaraAdminPolicy::~CynaraAdminPolicy()
183 free(this->privilege);
184 free(this->result_extra);
187 static bool checkCynaraError(int result, const std::string &msg)
190 case CYNARA_API_SUCCESS:
191 case CYNARA_API_ACCESS_ALLOWED:
193 case CYNARA_API_ACCESS_DENIED:
195 case CYNARA_API_OUT_OF_MEMORY:
196 ThrowMsg(CynaraException::OutOfMemory, msg);
197 case CYNARA_API_INVALID_PARAM:
198 ThrowMsg(CynaraException::InvalidParam, msg);
199 case CYNARA_API_SERVICE_NOT_AVAILABLE:
200 ThrowMsg(CynaraException::ServiceNotAvailable, msg);
201 case CYNARA_API_BUCKET_NOT_FOUND:
202 ThrowMsg(CynaraException::BucketNotFound, msg);
204 ThrowMsg(CynaraException::UnknownError, msg);
208 CynaraAdmin::CynaraAdmin()
211 cynara_admin_initialize(&m_CynaraAdmin),
212 "Cannot connect to Cynara administrative interface.");
215 CynaraAdmin::~CynaraAdmin()
217 cynara_admin_finish(m_CynaraAdmin);
220 CynaraAdmin &CynaraAdmin::getInstance()
222 static CynaraAdmin cynaraAdmin;
226 void CynaraAdmin::SetPolicies(const std::vector<CynaraAdminPolicy> &policies)
228 std::vector<const struct cynara_admin_policy *> pp_policies(policies.size() + 1);
230 LogDebug("Sending " << policies.size() << " policies to Cynara");
231 for (std::size_t i = 0; i < policies.size(); ++i) {
232 pp_policies[i] = static_cast<const struct cynara_admin_policy *>(&policies[i]);
233 LogDebug("policies[" << i << "] = {" <<
234 ".bucket = " << pp_policies[i]->bucket << ", " <<
235 ".client = " << pp_policies[i]->client << ", " <<
236 ".user = " << pp_policies[i]->user << ", " <<
237 ".privilege = " << pp_policies[i]->privilege << ", " <<
238 ".result = " << pp_policies[i]->result << ", " <<
239 ".result_extra = " << pp_policies[i]->result_extra << "}");
242 pp_policies[policies.size()] = nullptr;
245 cynara_admin_set_policies(m_CynaraAdmin, pp_policies.data()),
246 "Error while updating Cynara policy.");
249 void CynaraAdmin::UpdateAppPolicy(
250 const std::string &label,
251 const std::string &user,
252 const std::vector<std::string> &oldPrivileges,
253 const std::vector<std::string> &newPrivileges)
255 std::vector<CynaraAdminPolicy> policies;
257 // Perform sort-merge join on oldPrivileges and newPrivileges.
258 // Assume that they are already sorted and without duplicates.
259 auto oldIter = oldPrivileges.begin();
260 auto newIter = newPrivileges.begin();
262 while (oldIter != oldPrivileges.end() && newIter != newPrivileges.end()) {
263 int compare = oldIter->compare(*newIter);
265 LogDebug("(user = " << user << " label = " << label << ") " <<
266 "keeping privilege " << *newIter);
270 } else if (compare < 0) {
271 LogDebug("(user = " << user << " label = " << label << ") " <<
272 "removing privilege " << *oldIter);
273 policies.push_back(CynaraAdminPolicy(label, user, *oldIter,
274 CynaraAdminPolicy::Operation::Delete,
275 Buckets.at(Bucket::MANIFESTS)));
278 LogDebug("(user = " << user << " label = " << label << ") " <<
279 "adding privilege " << *newIter);
280 policies.push_back(CynaraAdminPolicy(label, user, *newIter,
281 CynaraAdminPolicy::Operation::Allow,
282 Buckets.at(Bucket::MANIFESTS)));
287 for (; oldIter != oldPrivileges.end(); ++oldIter) {
288 LogDebug("(user = " << user << " label = " << label << ") " <<
289 "removing privilege " << *oldIter);
290 policies.push_back(CynaraAdminPolicy(label, user, *oldIter,
291 CynaraAdminPolicy::Operation::Delete,
292 Buckets.at(Bucket::MANIFESTS)));
295 for (; newIter != newPrivileges.end(); ++newIter) {
296 LogDebug("(user = " << user << " label = " << label << ") " <<
297 "adding privilege " << *newIter);
298 policies.push_back(CynaraAdminPolicy(label, user, *newIter,
299 CynaraAdminPolicy::Operation::Allow,
300 Buckets.at(Bucket::MANIFESTS)));
303 SetPolicies(policies);
306 void CynaraAdmin::UserInit(uid_t uid, security_manager_user_type userType)
309 std::vector<CynaraAdminPolicy> policies;
312 case SM_USER_TYPE_SYSTEM:
313 bucket = Bucket::USER_TYPE_SYSTEM;
315 case SM_USER_TYPE_ADMIN:
316 bucket = Bucket::USER_TYPE_ADMIN;
318 case SM_USER_TYPE_GUEST:
319 bucket = Bucket::USER_TYPE_GUEST;
321 case SM_USER_TYPE_NORMAL:
322 bucket = Bucket::USER_TYPE_NORMAL;
324 case SM_USER_TYPE_ANY:
325 case SM_USER_TYPE_NONE:
326 case SM_USER_TYPE_END:
328 ThrowMsg(CynaraException::InvalidParam, "User type incorrect");
331 policies.push_back(CynaraAdminPolicy(CYNARA_ADMIN_WILDCARD,
332 std::to_string(static_cast<unsigned int>(uid)),
333 CYNARA_ADMIN_WILDCARD,
335 Buckets.at(Bucket::MAIN)));
337 CynaraAdmin::getInstance().SetPolicies(policies);
340 void CynaraAdmin::ListPolicies(
341 const std::string &bucketName,
342 const std::string &appId,
343 const std::string &user,
344 const std::string &privilege,
345 std::vector<CynaraAdminPolicy> &policies)
347 struct cynara_admin_policy ** pp_policies = nullptr;
350 cynara_admin_list_policies(m_CynaraAdmin, bucketName.c_str(), appId.c_str(),
351 user.c_str(), privilege.c_str(), &pp_policies),
352 "Error while getting list of policies for bucket: " + bucketName);
354 for (std::size_t i = 0; pp_policies[i] != nullptr; i++) {
355 policies.push_back(std::move(*static_cast<CynaraAdminPolicy*>(pp_policies[i])));
357 free(pp_policies[i]);
364 void CynaraAdmin::EmptyBucket(const std::string &bucketName, bool recursive, const std::string &client,
365 const std::string &user, const std::string &privilege)
368 cynara_admin_erase(m_CynaraAdmin, bucketName.c_str(), static_cast<int>(recursive),
369 client.c_str(), user.c_str(), privilege.c_str()),
370 "Error while emptying bucket: " + bucketName + ", filter (C, U, P): " +
371 client + ", " + user + ", " + privilege);
377 cynara_initialize(&m_Cynara, nullptr),
378 "Cannot connect to Cynara policy interface.");
383 cynara_finish(m_Cynara);
386 Cynara &Cynara::getInstance()
388 static Cynara cynara;
392 bool Cynara::check(const std::string &label, const std::string &privilege,
393 const std::string &user, const std::string &session)
395 return checkCynaraError(
396 cynara_check(m_Cynara,
397 label.c_str(), session.c_str(), user.c_str(), privilege.c_str()),
398 "Cannot check permission with Cynara.");
401 } // namespace SecurityManager