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
19 * @file service_impl.cpp
20 * @author Michal Witanowski <m.witanowski@samsung.com>
21 * @author Jacek Bukarewicz <j.bukarewicz@samsung.com>
22 * @author Rafal Krypa <r.krypa@samsung.com>
23 * @author Krzysztof Sasiak <k.sasiak@samsung.com>
24 * @brief Implementation of the service methods
34 #include <dpl/log/log.h>
35 #include <tzplatform_config.h>
37 #include "protocols.h"
38 #include "privilege_db.h"
40 #include "smack-rules.h"
41 #include "smack-labels.h"
42 #include "security-manager.h"
44 #include "service_impl.h"
46 namespace SecurityManager {
47 namespace ServiceImpl {
49 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
50 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
54 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
56 LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
57 LogDebug("[policy_entry] app: " << policyEntry.appId
58 << " user: " << policyEntry.user
59 << " privilege: " << policyEntry.privilege
60 << " current: " << policyEntry.currentLevel
61 << " max: " << policyEntry.maxLevel);
62 //automagically fill missing fields:
63 if (policyEntry.user.empty()) {
64 policyEntry.user = uidStr;
69 if (policyEntry.currentLevel.empty()) { //for admin
70 if (policyEntry.appId.empty()
71 || policyEntry.privilege.empty()) {
72 LogError("Bad admin update request");
73 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
76 if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
77 level = CYNARA_ADMIN_DELETE;
80 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
81 } catch (const std::out_of_range& e) {
82 LogError("policy max level cannot be: " << policyEntry.maxLevel);
83 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
88 } else if (policyEntry.maxLevel.empty()) { //for self
89 if (policyEntry.user.compare(uidStr)
90 || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
91 || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
92 || policyEntry.appId.empty()
93 || policyEntry.privilege.empty()) {
94 LogError("Bad privacy manager update request");
95 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
98 if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
99 level = CYNARA_ADMIN_DELETE;
102 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
103 } catch (const std::out_of_range& e) {
104 LogError("policy current level cannot be: " << policyEntry.currentLevel);
105 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
110 } else { //neither => bad request
111 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
114 if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
115 policyEntry.user = CYNARA_ADMIN_WILDCARD;
116 if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
117 policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
119 cyap = std::move(CynaraAdminPolicy(
120 policyEntry.appId.compare(SECURITY_MANAGER_ANY) ?
121 SmackLabels::generateAppLabel(policyEntry.appId) : CYNARA_ADMIN_WILDCARD,
123 policyEntry.privilege,
125 (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
127 LogDebug("Policy update request authenticated and validated successfully");
128 return SECURITY_MANAGER_API_SUCCESS;
130 } // end of anonymous namespace
132 static uid_t getGlobalUserId(void)
134 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
139 * Unifies user data of apps installed for all users
140 * @param uid peer's uid - may be changed during process
141 * @param cynaraUserStr string to which cynara user parameter will be put
143 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
145 static uid_t globaluid = getGlobalUserId();
146 if (uid == 0 || uid == globaluid) {
148 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
150 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
153 static inline bool isSubDir(const char *parent, const char *subdir)
155 while (*parent && *subdir)
156 if (*parent++ != *subdir++)
159 return (*subdir == '/');
162 static bool getUserAppDir(const uid_t &uid, std::string &userAppDir)
164 struct tzplatform_context *tz_ctx = nullptr;
166 if (tzplatform_context_create(&tz_ctx))
169 if (tzplatform_context_set_user(tz_ctx, uid)) {
170 tzplatform_context_destroy(tz_ctx);
175 enum tzplatform_variable id =
176 (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
177 const char *appDir = tzplatform_context_getenv(tz_ctx, id);
179 tzplatform_context_destroy(tz_ctx);
186 tzplatform_context_destroy(tz_ctx);
192 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
194 std::string userHome;
195 std::string userAppDir;
196 std::stringstream correctPath;
198 if (uid != getGlobalUserId())
199 LogDebug("Installation type: single user");
201 LogDebug("Installation type: global installation");
203 if (!getUserAppDir(uid, userAppDir)) {
204 LogError("Failed getting app dir for user uid: " << uid);
208 appPath = userAppDir;
210 correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
211 LogDebug("correctPath: " << correctPath.str());
213 for (const auto &appPath : req.appPaths) {
214 std::unique_ptr<char, std::function<void(void*)>> real_path(
215 realpath(appPath.first.c_str(), NULL), free);
216 if (!real_path.get()) {
217 LogError("realpath failed with '" << appPath.first.c_str()
218 << "' as parameter: " << strerror(errno));
221 LogDebug("Requested path is '" << appPath.first.c_str()
222 << "'. User's APPS_DIR is '" << userAppDir << "'");
223 if (!isSubDir(userAppDir.c_str(), real_path.get())) {
224 LogWarning("User's apps may have registered folders only in user's APPS_DIR");
228 if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
229 LogWarning("Installation is outside correct path: " << correctPath.str());
232 isCorrectPath = true;
234 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
235 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
236 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
243 int appInstall(const app_inst_req &req, uid_t uid)
245 std::vector<std::string> addedPermissions;
246 std::vector<std::string> removedPermissions;
247 std::vector<std::string> pkgContents;
249 bool isCorrectPath = false;
251 std::string appLabel;
252 std::string pkgLabel;
255 if (uid != req.uid) {
256 LogError("User " << uid <<
257 " is denied to install application for user " << req.uid);
258 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
264 checkGlobalUser(uid, uidstr);
266 if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
267 LogError("Request from uid " << uid << " for app installation denied");
268 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
271 // create null terminated array of strings for permissions
272 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
273 for (size_t i = 0; i < req.privileges.size(); ++i) {
274 LogDebug(" Permission = " << req.privileges[i]);
275 pp_permissions[i] = req.privileges[i].c_str();
277 pp_permissions[req.privileges.size()] = nullptr;
280 std::vector<std::string> oldAppPrivileges;
282 appLabel = SmackLabels::generateAppLabel(req.appId);
283 /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
284 pkgLabel = SmackLabels::generatePkgLabel(req.pkgId);
285 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
286 << ", uidstr " << uidstr
287 << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
289 PrivilegeDb::getInstance().BeginTransaction();
291 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
292 if (ret == true && pkg != req.pkgId) {
293 LogError("Application already installed with different package id");
294 PrivilegeDb::getInstance().RollbackTransaction();
295 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
297 PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
298 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
299 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
300 /* Get all application ids in the package to generate rules withing the package */
301 PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
302 CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
304 PrivilegeDb::getInstance().CommitTransaction();
305 LogDebug("Application installation commited to database");
306 } catch (const PrivilegeDb::Exception::IOError &e) {
307 LogError("Cannot access application database: " << e.DumpToString());
308 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
309 } catch (const PrivilegeDb::Exception::InternalError &e) {
310 PrivilegeDb::getInstance().RollbackTransaction();
311 LogError("Error while saving application info to database: " << e.DumpToString());
312 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
313 } catch (const CynaraException::Base &e) {
314 PrivilegeDb::getInstance().RollbackTransaction();
315 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
316 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
317 } catch (const SmackException::InvalidLabel &e) {
318 PrivilegeDb::getInstance().RollbackTransaction();
319 LogError("Error while generating Smack labels: " << e.DumpToString());
320 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
321 } catch (const std::bad_alloc &e) {
322 PrivilegeDb::getInstance().RollbackTransaction();
323 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
324 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
329 SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath);
332 for (const auto &appPath : req.appPaths) {
333 const std::string &path = appPath.first;
334 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
335 SmackLabels::setupPath(req.appId, path, pathType);
338 LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
339 << req.pkgId << ". Applications in package: " << pkgContents.size());
340 SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
341 } catch (const SmackException::Base &e) {
342 LogError("Error while applying Smack policy for application: " << e.DumpToString());
343 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
344 } catch (const std::bad_alloc &e) {
345 LogError("Memory allocation error: " << e.what());
346 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
349 return SECURITY_MANAGER_API_SUCCESS;
352 int appUninstall(const std::string &appId, uid_t uid)
355 std::string smackLabel;
356 std::vector<std::string> pkgContents;
357 bool appExists = true;
358 bool removePkg = false;
360 checkGlobalUser(uid, uidstr);
363 std::vector<std::string> oldAppPrivileges;
365 PrivilegeDb::getInstance().BeginTransaction();
366 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
367 LogWarning("Application " << appId <<
368 " not found in database while uninstalling");
369 PrivilegeDb::getInstance().RollbackTransaction();
372 smackLabel = SmackLabels::generateAppLabel(appId);
373 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
374 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
376 /* Before we remove the app from the database, let's fetch all apps in the package
377 that this app belongs to, this will allow us to remove all rules withing the
378 package that the app appears in */
379 PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
380 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
381 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
382 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
383 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
384 std::vector<std::string>());
385 PrivilegeDb::getInstance().CommitTransaction();
386 LogDebug("Application uninstallation commited to database");
388 } catch (const PrivilegeDb::Exception::IOError &e) {
389 LogError("Cannot access application database: " << e.DumpToString());
390 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
391 } catch (const PrivilegeDb::Exception::InternalError &e) {
392 PrivilegeDb::getInstance().RollbackTransaction();
393 LogError("Error while removing application info from database: " << e.DumpToString());
394 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
395 } catch (const CynaraException::Base &e) {
396 PrivilegeDb::getInstance().RollbackTransaction();
397 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
398 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
399 } catch (const SmackException::InvalidLabel &e) {
400 PrivilegeDb::getInstance().RollbackTransaction();
401 LogError("Error while generating Smack labels: " << e.DumpToString());
402 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
403 } catch (const std::bad_alloc &e) {
404 PrivilegeDb::getInstance().RollbackTransaction();
405 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
406 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
412 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
413 SmackRules::uninstallPackageRules(pkgId);
416 LogDebug("Removing smack rules for deleted appId " << appId);
417 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents);
419 } catch (const SmackException::Base &e) {
420 LogError("Error while removing Smack rules for application: " << e.DumpToString());
421 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
422 } catch (const std::bad_alloc &e) {
423 LogError("Memory allocation error: " << e.what());
424 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
427 return SECURITY_MANAGER_API_SUCCESS;
430 int getPkgId(const std::string &appId, std::string &pkgId)
432 LogDebug("appId: " << appId);
435 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
436 LogWarning("Application " << appId << " not found in database");
437 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
439 LogDebug("pkgId: " << pkgId);
441 } catch (const PrivilegeDb::Exception::Base &e) {
442 LogError("Error while getting pkgId from database: " << e.DumpToString());
443 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
446 return SECURITY_MANAGER_API_SUCCESS;
449 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set<gid_t> &gids)
453 std::string smackLabel;
454 std::string uidStr = std::to_string(uid);
455 std::string pidStr = std::to_string(pid);
457 LogDebug("appId: " << appId);
459 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
460 LogWarning("Application " << appId << " not found in database");
461 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
463 LogDebug("pkgId: " << pkgId);
465 smackLabel = SmackLabels::generatePkgLabel(pkgId);
466 LogDebug("smack label: " << smackLabel);
468 std::vector<std::string> privileges;
469 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
470 /*there is also a need of checking, if privilege is granted to all users*/
471 size_t tmp = privileges.size();
472 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
473 /*privileges needs to be sorted and with no duplications - for cynara sake*/
474 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
475 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
477 for (const auto &privilege : privileges) {
478 std::vector<std::string> gidsTmp;
479 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
480 if (!gidsTmp.empty()) {
481 LogDebug("Considering privilege " << privilege << " with " <<
482 gidsTmp.size() << " groups assigned");
483 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
484 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
486 struct group *grp = getgrnam(group.c_str());
488 LogError("No such group: " << group.c_str());
491 gids.insert(grp->gr_gid);
493 LogDebug("Cynara allowed, adding groups");
495 LogDebug("Cynara denied, not adding groups");
498 } catch (const PrivilegeDb::Exception::Base &e) {
499 LogError("Database error: " << e.DumpToString());
500 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
501 } catch (const CynaraException::Base &e) {
502 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
503 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
504 } catch (const SmackException::InvalidLabel &e) {
505 LogError("Error while generating Smack labels: " << e.DumpToString());
506 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
507 } catch (const std::bad_alloc &e) {
508 LogError("Memory allocation failed: " << e.what());
509 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
512 return SECURITY_MANAGER_API_SUCCESS;
515 int userAdd(uid_t uidAdded, int userType, uid_t uid)
518 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
521 CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
522 } catch (CynaraException::InvalidParam &e) {
523 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
525 return SECURITY_MANAGER_API_SUCCESS;
528 int userDelete(uid_t uidDeleted, uid_t uid)
530 int ret = SECURITY_MANAGER_API_SUCCESS;
532 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
534 /*Uninstall all user apps*/
535 std::vector<std::string> userApps;
537 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
538 } catch (const PrivilegeDb::Exception::Base &e) {
539 LogError("Error while getting user apps from database: " << e.DumpToString());
540 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
543 for (auto &app: userApps) {
544 if (appUninstall(app, uidDeleted) != SECURITY_MANAGER_API_SUCCESS) {
545 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
546 we do not have anything special to do about that matter - user will be deleted anyway.*/
547 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
551 CynaraAdmin::getInstance().UserRemove(uidDeleted);
556 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
562 } isAdmin = NOT_CHECKED;
565 std::string uidStr = std::to_string(uid);
566 std::string pidStr = std::to_string(pid);
568 if (policyEntries.size() == 0) {
569 LogError("Validation failed: policy update request is empty");
570 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
573 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
574 LogError("Not enough permission to call: " << __FUNCTION__);
575 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
578 std::vector<CynaraAdminPolicy> validatedPolicies;
580 for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
581 bool forAdmin = false;
582 CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
583 int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
585 if (forAdmin && (isAdmin == NOT_CHECKED)) {
586 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
589 if (ret == SECURITY_MANAGER_API_SUCCESS) {
591 || (forAdmin && (isAdmin == IS_ADMIN))) {
592 validatedPolicies.push_back(std::move(cyap));
594 LogError("Not enough privilege to enforce admin policy");
595 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
603 CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
605 } catch (const CynaraException::Base &e) {
606 LogError("Error while updating Cynara rules: " << e.DumpToString());
607 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
608 } catch (const std::bad_alloc &e) {
609 LogError("Memory allocation error while updating Cynara rules: " << e.what());
610 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
613 return SECURITY_MANAGER_API_SUCCESS;
616 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
617 const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
620 std::string uidStr = std::to_string(uid);
621 std::string pidStr = std::to_string(pid);
623 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
624 LogError("Not enough permission to call: " << __FUNCTION__);
625 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
628 LogDebug("Filter is: C: " << filter.appId
629 << ", U: " << filter.user
630 << ", P: " << filter.privilege
631 << ", current: " << filter.currentLevel
632 << ", max: " << filter.maxLevel
635 std::vector<CynaraAdminPolicy> listOfPolicies;
637 //convert appId to smack label
638 std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
639 std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
640 std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
642 LogDebug("App: " << filter.appId << ", Label: " << appLabel);
645 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
646 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
647 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
650 //Fetch privileges from ADMIN bucket
651 CynaraAdmin::getInstance().ListPolicies(
652 CynaraAdmin::Buckets.at(Bucket::ADMIN),
658 LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
660 if (uidStr.compare(user)) {
661 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
662 LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
666 //Fetch privileges from PRIVACY_MANAGER bucket
667 CynaraAdmin::getInstance().ListPolicies(
668 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
674 LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
677 for (const auto &policy : listOfPolicies) {
678 //ignore "jump to bucket" entries
679 if (policy.result == CYNARA_ADMIN_BUCKET)
684 pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
685 pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
686 pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
687 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
690 // All policy entries in PRIVACY_MANAGER should be fully-qualified
691 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
692 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
693 policy.client, policy.user, policy.privilege));
695 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
696 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
701 "[policy_entry] app: " << pe.appId
702 << " user: " << pe.user
703 << " privilege: " << pe.privilege
704 << " current: " << pe.currentLevel
705 << " max: " << pe.maxLevel
708 policyEntries.push_back(pe);
711 } catch (const CynaraException::Base &e) {
712 LogError("Error while listing Cynara rules: " << e.DumpToString());
713 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
714 } catch (const SmackException::InvalidLabel &e) {
715 LogError("Error while generating Smack labels: " << e.DumpToString());
716 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
717 } catch (const std::bad_alloc &e) {
718 LogError("Memory allocation error while listing Cynara rules: " << e.what());
719 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
723 return SECURITY_MANAGER_API_SUCCESS;
726 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
729 std::string uidStr = std::to_string(uid);
730 std::string pidStr = std::to_string(pid);
732 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
733 LogWarning("Not enough permission to call: " << __FUNCTION__);
734 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
737 LogDebug("Filter is: C: " << filter.appId
738 << ", U: " << filter.user
739 << ", P: " << filter.privilege
740 << ", current: " << filter.currentLevel
741 << ", max: " << filter.maxLevel
744 std::vector<uid_t> listOfUsers;
746 if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
747 LogDebug("User is privileged");
748 if (filter.user.compare(SECURITY_MANAGER_ANY)) {
749 LogDebug("Limitting Cynara query to user: " << filter.user);
751 listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
752 } catch (std::invalid_argument &e) {
753 LogError("Invalid UID: " << e.what());
756 CynaraAdmin::getInstance().ListUsers(listOfUsers);
758 LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
759 LogDebug("Fetching personal policy for user: " << uid);
760 listOfUsers.push_back(uid);
762 LogDebug("Fetching policy for " << listOfUsers.size() << " users");
764 for (const uid_t &uid : listOfUsers) {
765 LogDebug("User: " << uid);
766 std::string userStr = std::to_string(uid);
767 std::vector<std::string> listOfApps;
769 if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
770 LogDebug("Limitting Cynara query to app: " << filter.appId);
771 listOfApps.push_back(filter.appId);
773 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
774 LogDebug("Found apps: " << listOfApps.size());
777 for (const std::string &appId : listOfApps) {
778 LogDebug("App: " << appId);
779 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
780 std::vector<std::string> listOfPrivileges;
782 // FIXME: also fetch privileges of global applications
783 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
785 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
786 LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
787 // FIXME: this filtering should be already performed by method fetching the privileges
788 if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
789 filter.privilege) == listOfPrivileges.end()) {
790 LogDebug("Application " << appId <<
791 " doesn't have the filteres privilege " << filter.privilege);
794 listOfPrivileges.clear();
795 listOfPrivileges.push_back(filter.privilege);
798 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
800 for (const std::string &privilege : listOfPrivileges) {
801 LogDebug("Privilege: " << privilege);
806 pe.privilege = privilege;
808 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
809 CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
810 smackLabelForApp, userStr, privilege));
812 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
813 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
814 smackLabelForApp, userStr, privilege));
817 "[policy_entry] app: " << pe.appId
818 << " user: " << pe.user
819 << " privilege: " << pe.privilege
820 << " current: " << pe.currentLevel
821 << " max: " << pe.maxLevel
824 policyEntries.push_back(pe);
829 } catch (const CynaraException::Base &e) {
830 LogError("Error while listing Cynara rules: " << e.DumpToString());
831 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
832 } catch (const SmackException::InvalidLabel &e) {
833 LogError("Error while generating Smack labels: " << e.DumpToString());
834 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
835 } catch (const std::bad_alloc &e) {
836 LogError("Memory allocation error while listing Cynara rules: " << e.what());
837 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
840 return SECURITY_MANAGER_API_SUCCESS;
843 int policyGetDesc(std::vector<std::string> &levels)
845 int ret = SECURITY_MANAGER_API_SUCCESS;
848 CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
849 } catch (const CynaraException::OutOfMemory &e) {
850 LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
851 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
852 } catch (const CynaraException::InvalidParam &e) {
853 LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
854 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
855 } catch (const CynaraException::ServiceNotAvailable &e) {
856 LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
857 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
858 } catch (const CynaraException::Base &e) {
859 LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
860 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
866 } /* namespace ServiceImpl */
867 } /* namespace SecurityManager */