2 * Copyright (c) 2014-2015 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
30 #include <sys/socket.h>
35 #include <dpl/log/log.h>
36 #include <tzplatform_config.h>
39 #include "protocols.h"
40 #include "privilege_db.h"
42 #include "smack-rules.h"
43 #include "smack-labels.h"
44 #include "security-manager.h"
45 #include "zone-utils.h"
47 #include "service_impl.h"
48 #include "master-req.h"
50 namespace SecurityManager {
52 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
53 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
57 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
59 LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
60 LogDebug("[policy_entry] app: " << policyEntry.appId
61 << " user: " << policyEntry.user
62 << " privilege: " << policyEntry.privilege
63 << " current: " << policyEntry.currentLevel
64 << " max: " << policyEntry.maxLevel);
65 //automagically fill missing fields:
66 if (policyEntry.user.empty()) {
67 policyEntry.user = uidStr;
72 if (policyEntry.currentLevel.empty()) { //for admin
73 if (policyEntry.appId.empty()
74 || policyEntry.privilege.empty()) {
75 LogError("Bad admin update request");
76 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
79 if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
80 level = CYNARA_ADMIN_DELETE;
83 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
84 } catch (const std::out_of_range& e) {
85 LogError("policy max level cannot be: " << policyEntry.maxLevel);
86 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
91 } else if (policyEntry.maxLevel.empty()) { //for self
92 if (policyEntry.user.compare(uidStr)
93 || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
94 || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
95 || policyEntry.appId.empty()
96 || policyEntry.privilege.empty()) {
97 LogError("Bad privacy manager update request");
98 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
101 if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
102 level = CYNARA_ADMIN_DELETE;
105 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
106 } catch (const std::out_of_range& e) {
107 LogError("policy current level cannot be: " << policyEntry.currentLevel);
108 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
113 } else { //neither => bad request
114 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
117 if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
118 policyEntry.user = CYNARA_ADMIN_WILDCARD;
119 if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
120 policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
122 cyap = std::move(CynaraAdminPolicy(
123 policyEntry.appId.compare(SECURITY_MANAGER_ANY) ?
124 SmackLabels::generateAppLabel(policyEntry.appId) : CYNARA_ADMIN_WILDCARD,
126 policyEntry.privilege,
128 (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
130 LogDebug("Policy update request authenticated and validated successfully");
131 return SECURITY_MANAGER_API_SUCCESS;
133 } // end of anonymous namespace
135 ServiceImpl::ServiceImpl()
139 ServiceImpl::~ServiceImpl()
143 uid_t ServiceImpl::getGlobalUserId(void)
145 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
150 * Unifies user data of apps installed for all users
151 * @param uid peer's uid - may be changed during process
152 * @param cynaraUserStr string to which cynara user parameter will be put
154 void ServiceImpl::checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
156 static uid_t globaluid = getGlobalUserId();
157 if (uid == 0 || uid == globaluid) {
159 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
161 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
165 bool ServiceImpl::isSubDir(const char *parent, const char *subdir)
167 while (*parent && *subdir)
168 if (*parent++ != *subdir++)
171 return (*subdir == '/');
174 bool ServiceImpl::getUserAppDir(const uid_t &uid, std::string &userAppDir)
176 struct tzplatform_context *tz_ctx = nullptr;
178 if (tzplatform_context_create(&tz_ctx))
181 if (tzplatform_context_set_user(tz_ctx, uid)) {
182 tzplatform_context_destroy(tz_ctx);
187 enum tzplatform_variable id =
188 (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
189 const char *appDir = tzplatform_context_getenv(tz_ctx, id);
191 tzplatform_context_destroy(tz_ctx);
198 tzplatform_context_destroy(tz_ctx);
204 bool ServiceImpl::installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
206 std::string userHome;
207 std::string userAppDir;
208 std::stringstream correctPath;
210 if (uid != getGlobalUserId())
211 LogDebug("Installation type: single user");
213 LogDebug("Installation type: global installation");
215 if (!getUserAppDir(uid, userAppDir)) {
216 LogError("Failed getting app dir for user uid: " << uid);
220 appPath = userAppDir;
222 correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
223 LogDebug("correctPath: " << correctPath.str());
225 for (const auto &appPath : req.appPaths) {
226 std::unique_ptr<char, std::function<void(void*)>> real_path(
227 realpath(appPath.first.c_str(), NULL), free);
228 if (!real_path.get()) {
229 LogError("realpath failed with '" << appPath.first.c_str()
230 << "' as parameter: " << strerror(errno));
233 LogDebug("Requested path is '" << appPath.first.c_str()
234 << "'. User's APPS_DIR is '" << userAppDir << "'");
235 if (!isSubDir(userAppDir.c_str(), real_path.get())) {
236 LogWarning("User's apps may have registered folders only in user's APPS_DIR");
240 if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
241 LogWarning("Installation is outside correct path: " << correctPath.str());
244 isCorrectPath = true;
246 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
247 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
248 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
255 bool ServiceImpl::getZoneId(std::string &zoneId)
257 if (!getZoneIdFromPid(getpid(), zoneId)) {
258 LogError("Failed to get zone ID from current PID");
262 // This function should be called under slave mode only - assumes, that we work inside zone
263 if (zoneId == ZONE_HOST) {
264 LogError("We should not run in host - refusing request");
271 int ServiceImpl::appInstall(const app_inst_req &req, uid_t uid, bool isSlave)
273 std::vector<std::string> addedPermissions;
274 std::vector<std::string> removedPermissions;
275 std::vector<std::string> pkgContents;
277 bool isCorrectPath = false;
279 std::string appLabel;
280 std::string pkgLabel;
284 if (!getZoneId(zoneId)) {
285 LogError("Failed to get Zone ID.");
286 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
291 if (uid != req.uid) {
292 LogError("User " << uid <<
293 " is denied to install application for user " << req.uid);
294 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
300 checkGlobalUser(uid, uidstr);
302 if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
303 LogError("Request from uid " << uid << " for app installation denied");
304 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
308 std::vector<std::string> oldAppPrivileges;
310 appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
311 /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
312 pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
313 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
314 << ", uidstr " << uidstr
315 << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
317 PrivilegeDb::getInstance().BeginTransaction();
319 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
320 if (ret == true && pkg != req.pkgId) {
321 LogError("Application already installed with different package id");
322 PrivilegeDb::getInstance().RollbackTransaction();
323 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
325 PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
326 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
327 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
328 /* Get all application ids in the package to generate rules withing the package */
329 PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
332 int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
334 if (ret != SECURITY_MANAGER_API_SUCCESS) {
335 PrivilegeDb::getInstance().RollbackTransaction();
336 LogError("Error while processing request on master: " << ret);
340 CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
344 PrivilegeDb::getInstance().CommitTransaction();
345 LogDebug("Application installation commited to database");
346 } catch (const PrivilegeDb::Exception::IOError &e) {
347 LogError("Cannot access application database: " << e.DumpToString());
348 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
349 } catch (const PrivilegeDb::Exception::InternalError &e) {
350 PrivilegeDb::getInstance().RollbackTransaction();
351 LogError("Error while saving application info to database: " << e.DumpToString());
352 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
353 } catch (const CynaraException::Base &e) {
354 PrivilegeDb::getInstance().RollbackTransaction();
355 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
356 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
357 } catch (const SmackException::InvalidLabel &e) {
358 PrivilegeDb::getInstance().RollbackTransaction();
359 LogError("Error while generating Smack labels: " << e.DumpToString());
360 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
361 } catch (const std::bad_alloc &e) {
362 PrivilegeDb::getInstance().RollbackTransaction();
363 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
364 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
369 SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
372 for (const auto &appPath : req.appPaths) {
373 const std::string &path = appPath.first;
374 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
375 SmackLabels::setupPath(req.appId, path, pathType, zoneId);
379 LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
380 << req.pkgId << ". Applications in package: " << pkgContents.size());
381 int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
382 if (ret != SECURITY_MANAGER_API_SUCCESS) {
383 LogError("Master failed to apply package-specific smack rules: " << ret);
387 LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
388 << req.pkgId << ". Applications in package: " << pkgContents.size());
389 SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
391 } catch (const SmackException::Base &e) {
392 LogError("Error while applying Smack policy for application: " << e.DumpToString());
393 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
394 } catch (const SecurityManager::Exception &e) {
395 LogError("Security Manager exception: " << e.DumpToString());
396 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
397 }catch (const std::bad_alloc &e) {
398 LogError("Memory allocation error: " << e.what());
399 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
402 return SECURITY_MANAGER_API_SUCCESS;
405 int ServiceImpl::appUninstall(const std::string &appId, uid_t uid, bool isSlave)
408 std::string smackLabel;
409 std::vector<std::string> pkgContents;
410 bool appExists = true;
411 bool removePkg = false;
413 checkGlobalUser(uid, uidstr);
417 if (!getZoneId(zoneId)) {
418 LogError("Failed to get Zone ID.");
419 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
424 std::vector<std::string> oldAppPrivileges;
426 PrivilegeDb::getInstance().BeginTransaction();
427 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
428 LogWarning("Application " << appId <<
429 " not found in database while uninstalling");
430 PrivilegeDb::getInstance().RollbackTransaction();
433 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
434 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
435 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
437 /* Before we remove the app from the database, let's fetch all apps in the package
438 that this app belongs to, this will allow us to remove all rules withing the
439 package that the app appears in */
440 PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
441 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
442 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
443 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
446 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
447 std::vector<std::string>());
448 if (ret != SECURITY_MANAGER_API_SUCCESS) {
449 PrivilegeDb::getInstance().RollbackTransaction();
450 LogError("Error while processing request on master: " << ret);
454 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
455 std::vector<std::string>());
458 PrivilegeDb::getInstance().CommitTransaction();
459 LogDebug("Application uninstallation commited to database");
461 } catch (const PrivilegeDb::Exception::IOError &e) {
462 LogError("Cannot access application database: " << e.DumpToString());
463 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
464 } catch (const PrivilegeDb::Exception::InternalError &e) {
465 PrivilegeDb::getInstance().RollbackTransaction();
466 LogError("Error while removing application info from database: " << e.DumpToString());
467 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
468 } catch (const CynaraException::Base &e) {
469 PrivilegeDb::getInstance().RollbackTransaction();
470 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
471 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
472 } catch (const SmackException::InvalidLabel &e) {
473 PrivilegeDb::getInstance().RollbackTransaction();
474 LogError("Error while generating Smack labels: " << e.DumpToString());
475 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
476 } catch (const std::bad_alloc &e) {
477 PrivilegeDb::getInstance().RollbackTransaction();
478 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
479 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
485 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
487 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
488 if (ret != SECURITY_MANAGER_API_SUCCESS) {
489 LogError("Error while processing uninstall request on master: " << ret);
494 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
495 SmackRules::uninstallPackageRules(pkgId);
498 LogDebug ("Removing smack rules for deleted appId " << appId);
499 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
501 } catch (const SmackException::Base &e) {
502 LogError("Error while removing Smack rules for application: " << e.DumpToString());
503 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
504 } catch (const SecurityManager::Exception &e) {
505 LogError("Security Manager error: " << e.DumpToString());
506 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
507 } catch (const std::bad_alloc &e) {
508 LogError("Memory allocation error: " << e.what());
509 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
513 return SECURITY_MANAGER_API_SUCCESS;
516 int ServiceImpl::getPkgId(const std::string &appId, std::string &pkgId)
518 LogDebug("appId: " << appId);
521 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
522 LogWarning("Application " << appId << " not found in database");
523 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
525 LogDebug("pkgId: " << pkgId);
527 } catch (const PrivilegeDb::Exception::Base &e) {
528 LogError("Error while getting pkgId from database: " << e.DumpToString());
529 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
532 return SECURITY_MANAGER_API_SUCCESS;
535 int ServiceImpl::getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
536 std::unordered_set<gid_t> &gids)
538 // FIXME Temporary solution, see below
541 if (!getZoneId(zoneId)) {
542 LogError("Failed to get Zone ID.");
543 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
549 std::string smackLabel;
550 std::string uidStr = std::to_string(uid);
551 std::string pidStr = std::to_string(pid);
553 LogDebug("appId: " << appId);
555 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
556 LogWarning("Application " << appId << " not found in database");
557 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
559 LogDebug("pkgId: " << pkgId);
561 // FIXME getAppGroups should work without generating zone-specific labels when
562 // Smack Namespaces will work
563 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
564 LogDebug("smack label: " << smackLabel);
566 std::vector<std::string> privileges;
567 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
568 /*there is also a need of checking, if privilege is granted to all users*/
569 size_t tmp = privileges.size();
570 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
571 /*privileges needs to be sorted and with no duplications - for cynara sake*/
572 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
573 privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
575 for (const auto &privilege : privileges) {
576 std::vector<std::string> gidsTmp;
577 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
578 if (!gidsTmp.empty()) {
579 LogDebug("Considering privilege " << privilege << " with " <<
580 gidsTmp.size() << " groups assigned");
581 // TODO: create method in Cynara class for fetching all privileges of an application
582 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
583 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
584 struct group *grp = getgrnam(group.c_str());
586 LogError("No such group: " << group.c_str());
589 gids.insert(grp->gr_gid);
591 LogDebug("Cynara allowed, adding groups");
593 LogDebug("Cynara denied, not adding groups");
596 } catch (const PrivilegeDb::Exception::Base &e) {
597 LogError("Database error: " << e.DumpToString());
598 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
599 } catch (const CynaraException::Base &e) {
600 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
601 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
602 } catch (const SmackException::InvalidLabel &e) {
603 LogError("Error while generating Smack labels: " << e.DumpToString());
604 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
605 } catch (const std::bad_alloc &e) {
606 LogError("Memory allocation failed: " << e.what());
607 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
610 return SECURITY_MANAGER_API_SUCCESS;
613 int ServiceImpl::userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
616 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
619 int ret = MasterReq::CynaraUserInit(uidAdded,
620 static_cast<security_manager_user_type>(userType));
621 if (ret != SECURITY_MANAGER_API_SUCCESS) {
622 LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
627 CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
628 } catch (CynaraException::InvalidParam &e) {
629 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
633 return SECURITY_MANAGER_API_SUCCESS;
636 int ServiceImpl::userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
638 int ret = SECURITY_MANAGER_API_SUCCESS;
640 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
642 /*Uninstall all user apps*/
643 std::vector<std::string> userApps;
645 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
646 } catch (const PrivilegeDb::Exception::Base &e) {
647 LogError("Error while getting user apps from database: " << e.DumpToString());
648 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
651 for (auto &app: userApps) {
652 if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
653 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
654 we do not have anything special to do about that matter - user will be deleted anyway.*/
655 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
660 int ret = MasterReq::CynaraUserRemove(uidDeleted);
662 LogError("Master failed to delete user " << uidDeleted);
666 CynaraAdmin::getInstance().UserRemove(uidDeleted);
672 int ServiceImpl::policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
678 } isAdmin = NOT_CHECKED;
681 std::string uidStr = std::to_string(uid);
682 std::string pidStr = std::to_string(pid);
684 if (policyEntries.size() == 0) {
685 LogError("Validation failed: policy update request is empty");
686 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
689 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
690 LogError("Not enough permission to call: " << __FUNCTION__);
691 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
694 std::vector<CynaraAdminPolicy> validatedPolicies;
696 for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
697 bool forAdmin = false;
698 CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
699 int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
701 if (forAdmin && (isAdmin == NOT_CHECKED)) {
702 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
705 if (ret == SECURITY_MANAGER_API_SUCCESS) {
707 || (forAdmin && (isAdmin == IS_ADMIN))) {
708 validatedPolicies.push_back(std::move(cyap));
710 LogError("Not enough privilege to enforce admin policy");
711 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
719 CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
721 } catch (const CynaraException::Base &e) {
722 LogError("Error while updating Cynara rules: " << e.DumpToString());
723 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
724 } catch (const std::bad_alloc &e) {
725 LogError("Memory allocation error while updating Cynara rules: " << e.what());
726 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
729 return SECURITY_MANAGER_API_SUCCESS;
732 int ServiceImpl::getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
733 const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
736 std::string uidStr = std::to_string(uid);
737 std::string pidStr = std::to_string(pid);
739 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
740 LogError("Not enough permission to call: " << __FUNCTION__);
741 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
744 LogDebug("Filter is: C: " << filter.appId
745 << ", U: " << filter.user
746 << ", P: " << filter.privilege
747 << ", current: " << filter.currentLevel
748 << ", max: " << filter.maxLevel
751 std::vector<CynaraAdminPolicy> listOfPolicies;
753 //convert appId to smack label
754 std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
755 std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
756 std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
758 LogDebug("App: " << filter.appId << ", Label: " << appLabel);
761 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
762 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
763 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
766 //Fetch privileges from ADMIN bucket
767 CynaraAdmin::getInstance().ListPolicies(
768 CynaraAdmin::Buckets.at(Bucket::ADMIN),
774 LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
776 if (uidStr.compare(user)) {
777 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
778 LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
782 //Fetch privileges from PRIVACY_MANAGER bucket
783 CynaraAdmin::getInstance().ListPolicies(
784 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
790 LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
793 for (const auto &policy : listOfPolicies) {
794 //ignore "jump to bucket" entries
795 if (policy.result == CYNARA_ADMIN_BUCKET)
800 pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
801 pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
802 pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
803 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
806 // All policy entries in PRIVACY_MANAGER should be fully-qualified
807 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
808 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
809 policy.client, policy.user, policy.privilege));
811 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
812 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
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);
827 } catch (const CynaraException::Base &e) {
828 LogError("Error while listing Cynara rules: " << e.DumpToString());
829 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
830 } catch (const SmackException::InvalidLabel &e) {
831 LogError("Error while generating Smack labels: " << e.DumpToString());
832 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
833 } catch (const std::bad_alloc &e) {
834 LogError("Memory allocation error while listing Cynara rules: " << e.what());
835 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
839 return SECURITY_MANAGER_API_SUCCESS;
842 int ServiceImpl::getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
845 std::string uidStr = std::to_string(uid);
846 std::string pidStr = std::to_string(pid);
848 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
849 LogWarning("Not enough permission to call: " << __FUNCTION__);
850 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
853 LogDebug("Filter is: C: " << filter.appId
854 << ", U: " << filter.user
855 << ", P: " << filter.privilege
856 << ", current: " << filter.currentLevel
857 << ", max: " << filter.maxLevel
860 std::vector<uid_t> listOfUsers;
862 if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
863 LogDebug("User is privileged");
864 if (filter.user.compare(SECURITY_MANAGER_ANY)) {
865 LogDebug("Limitting Cynara query to user: " << filter.user);
867 listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
868 } catch (std::invalid_argument &e) {
869 LogError("Invalid UID: " << e.what());
872 CynaraAdmin::getInstance().ListUsers(listOfUsers);
874 LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
875 LogDebug("Fetching personal policy for user: " << uid);
876 listOfUsers.push_back(uid);
878 LogDebug("Fetching policy for " << listOfUsers.size() << " users");
880 for (const uid_t &uid : listOfUsers) {
881 LogDebug("User: " << uid);
882 std::string userStr = std::to_string(uid);
883 std::vector<std::string> listOfApps;
885 if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
886 LogDebug("Limitting Cynara query to app: " << filter.appId);
887 listOfApps.push_back(filter.appId);
889 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
890 LogDebug("Found apps: " << listOfApps.size());
893 for (const std::string &appId : listOfApps) {
894 LogDebug("App: " << appId);
895 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
896 std::vector<std::string> listOfPrivileges;
898 // FIXME: also fetch privileges of global applications
899 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
901 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
902 LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
903 // FIXME: this filtering should be already performed by method fetching the privileges
904 if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
905 filter.privilege) == listOfPrivileges.end()) {
906 LogDebug("Application " << appId <<
907 " doesn't have the filteres privilege " << filter.privilege);
910 listOfPrivileges.clear();
911 listOfPrivileges.push_back(filter.privilege);
914 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
916 for (const std::string &privilege : listOfPrivileges) {
917 LogDebug("Privilege: " << privilege);
922 pe.privilege = privilege;
924 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
925 CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
926 smackLabelForApp, userStr, privilege));
928 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
929 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
930 smackLabelForApp, userStr, privilege));
933 "[policy_entry] app: " << pe.appId
934 << " user: " << pe.user
935 << " privilege: " << pe.privilege
936 << " current: " << pe.currentLevel
937 << " max: " << pe.maxLevel
940 policyEntries.push_back(pe);
945 } catch (const CynaraException::Base &e) {
946 LogError("Error while listing Cynara rules: " << e.DumpToString());
947 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
948 } catch (const SmackException::InvalidLabel &e) {
949 LogError("Error while generating Smack labels: " << e.DumpToString());
950 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
951 } catch (const std::bad_alloc &e) {
952 LogError("Memory allocation error while listing Cynara rules: " << e.what());
953 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
956 return SECURITY_MANAGER_API_SUCCESS;
959 int ServiceImpl::policyGetDesc(std::vector<std::string> &levels)
961 int ret = SECURITY_MANAGER_API_SUCCESS;
964 CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
965 } catch (const CynaraException::OutOfMemory &e) {
966 LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
967 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
968 } catch (const CynaraException::InvalidParam &e) {
969 LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
970 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
971 } catch (const CynaraException::ServiceNotAvailable &e) {
972 LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
973 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
974 } catch (const CynaraException::Base &e) {
975 LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
976 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
982 int ServiceImpl::getPrivilegesMappings(const std::string &version_from,
983 const std::string &version_to,
984 const std::vector<std::string> &privileges,
985 std::vector<std::string> &mappings)
989 std::string finalVersionTo;
990 if (version_to.empty()) {
991 finalVersionTo = Config::PRIVILEGE_VERSION;
993 finalVersionTo = version_to;
996 PrivilegeDb::getInstance().BeginTransaction();
997 if (privileges.size() == 0) {
998 PrivilegeDb::getInstance().GetDefaultMapping(version_from, finalVersionTo, mappings);
999 } else if ( privileges.size() == 1) {
1000 PrivilegeDb::getInstance().GetPrivilegeMappings(version_from, finalVersionTo,
1001 privileges.front(), mappings);
1003 PrivilegeDb::getInstance().GetPrivilegesMappings(version_from, finalVersionTo,
1004 privileges, mappings);
1006 PrivilegeDb::getInstance().CommitTransaction();
1007 return SECURITY_MANAGER_API_SUCCESS;
1008 } catch (const PrivilegeDb::Exception::IOError &e) {
1009 LogError("Cannot access application database: " << e.DumpToString());
1010 errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1011 } catch (const PrivilegeDb::Exception::InternalError &e) {
1012 LogError("Error while getting privilege mapping from database: " << e.DumpToString());
1013 errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1014 } catch (const std::bad_alloc &e) {
1015 LogError("Memory allocation failed: " << e.what());
1016 errorRet = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
1017 } catch (const std::exception &e) {
1018 LogError("Some exception thrown : " << e.what());
1019 errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1021 LogError("Unknown exception thrown");
1022 errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1024 PrivilegeDb::getInstance().RollbackTransaction();
1028 int ServiceImpl::policyGetGroups(std::vector<std::string> &groups)
1030 int ret = SECURITY_MANAGER_API_SUCCESS;
1033 PrivilegeDb::getInstance().GetGroups(groups);
1034 } catch (const PrivilegeDb::Exception::Base &e) {
1035 LogError("Error while getting groups from database: " << e.DumpToString());
1036 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1042 } /* namespace SecurityManager */