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 {
51 namespace ServiceImpl {
53 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
54 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
58 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
60 LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
61 LogDebug("[policy_entry] app: " << policyEntry.appId
62 << " user: " << policyEntry.user
63 << " privilege: " << policyEntry.privilege
64 << " current: " << policyEntry.currentLevel
65 << " max: " << policyEntry.maxLevel);
66 //automagically fill missing fields:
67 if (policyEntry.user.empty()) {
68 policyEntry.user = uidStr;
73 if (policyEntry.currentLevel.empty()) { //for admin
74 if (policyEntry.appId.empty()
75 || policyEntry.privilege.empty()) {
76 LogError("Bad admin update request");
77 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
80 if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
81 level = CYNARA_ADMIN_DELETE;
84 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
85 } catch (const std::out_of_range& e) {
86 LogError("policy max level cannot be: " << policyEntry.maxLevel);
87 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
92 } else if (policyEntry.maxLevel.empty()) { //for self
93 if (policyEntry.user.compare(uidStr)
94 || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
95 || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
96 || policyEntry.appId.empty()
97 || policyEntry.privilege.empty()) {
98 LogError("Bad privacy manager update request");
99 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
102 if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
103 level = CYNARA_ADMIN_DELETE;
106 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
107 } catch (const std::out_of_range& e) {
108 LogError("policy current level cannot be: " << policyEntry.currentLevel);
109 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
114 } else { //neither => bad request
115 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
118 if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
119 policyEntry.user = CYNARA_ADMIN_WILDCARD;
120 if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
121 policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
123 cyap = std::move(CynaraAdminPolicy(
124 policyEntry.appId.compare(SECURITY_MANAGER_ANY) ?
125 SmackLabels::generateAppLabel(policyEntry.appId) : CYNARA_ADMIN_WILDCARD,
127 policyEntry.privilege,
129 (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
131 LogDebug("Policy update request authenticated and validated successfully");
132 return SECURITY_MANAGER_API_SUCCESS;
134 } // end of anonymous namespace
136 static uid_t getGlobalUserId(void)
138 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
143 * Unifies user data of apps installed for all users
144 * @param uid peer's uid - may be changed during process
145 * @param cynaraUserStr string to which cynara user parameter will be put
147 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
149 static uid_t globaluid = getGlobalUserId();
150 if (uid == 0 || uid == globaluid) {
152 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
154 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
157 static inline bool isSubDir(const char *parent, const char *subdir)
159 while (*parent && *subdir)
160 if (*parent++ != *subdir++)
163 return (*subdir == '/');
166 bool getPeerID(int sock, uid_t &uid, pid_t &pid)
169 socklen_t len = sizeof(cr);
171 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
180 static bool getUserAppDir(const uid_t &uid, std::string &userAppDir)
182 struct tzplatform_context *tz_ctx = nullptr;
184 if (tzplatform_context_create(&tz_ctx))
187 if (tzplatform_context_set_user(tz_ctx, uid)) {
188 tzplatform_context_destroy(tz_ctx);
193 enum tzplatform_variable id =
194 (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
195 const char *appDir = tzplatform_context_getenv(tz_ctx, id);
197 tzplatform_context_destroy(tz_ctx);
204 tzplatform_context_destroy(tz_ctx);
210 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
212 std::string userHome;
213 std::string userAppDir;
214 std::stringstream correctPath;
216 if (uid != getGlobalUserId())
217 LogDebug("Installation type: single user");
219 LogDebug("Installation type: global installation");
221 if (!getUserAppDir(uid, userAppDir)) {
222 LogError("Failed getting app dir for user uid: " << uid);
226 appPath = userAppDir;
228 correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
229 LogDebug("correctPath: " << correctPath.str());
231 for (const auto &appPath : req.appPaths) {
232 std::unique_ptr<char, std::function<void(void*)>> real_path(
233 realpath(appPath.first.c_str(), NULL), free);
234 if (!real_path.get()) {
235 LogError("realpath failed with '" << appPath.first.c_str()
236 << "' as parameter: " << strerror(errno));
239 LogDebug("Requested path is '" << appPath.first.c_str()
240 << "'. User's APPS_DIR is '" << userAppDir << "'");
241 if (!isSubDir(userAppDir.c_str(), real_path.get())) {
242 LogWarning("User's apps may have registered folders only in user's APPS_DIR");
246 if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
247 LogWarning("Installation is outside correct path: " << correctPath.str());
250 isCorrectPath = true;
252 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
253 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
254 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
261 static inline bool getZoneId(std::string &zoneId)
263 if (!getZoneIdFromPid(getpid(), zoneId)) {
264 LogError("Failed to get zone ID from current PID");
268 // This function should be called under slave mode only - assumes, that we work inside zone
269 if (zoneId == ZONE_HOST) {
270 LogError("We should not run in host - refusing request");
277 int appInstall(const app_inst_req &req, uid_t uid, bool isSlave)
279 std::vector<std::string> addedPermissions;
280 std::vector<std::string> removedPermissions;
281 std::vector<std::string> pkgContents;
283 bool isCorrectPath = false;
285 std::string appLabel;
286 std::string pkgLabel;
290 if (!getZoneId(zoneId)) {
291 LogError("Failed to get Zone ID.");
292 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
297 if (uid != req.uid) {
298 LogError("User " << uid <<
299 " is denied to install application for user " << req.uid);
300 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
306 checkGlobalUser(uid, uidstr);
308 if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
309 LogError("Request from uid " << uid << " for app installation denied");
310 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
314 std::vector<std::string> oldAppPrivileges;
316 appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
317 /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
318 pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
319 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
320 << ", uidstr " << uidstr
321 << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
323 PrivilegeDb::getInstance().BeginTransaction();
325 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
326 if (ret == true && pkg != req.pkgId) {
327 LogError("Application already installed with different package id");
328 PrivilegeDb::getInstance().RollbackTransaction();
329 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
331 PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
332 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
333 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
334 /* Get all application ids in the package to generate rules withing the package */
335 PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
338 int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
340 if (ret != SECURITY_MANAGER_API_SUCCESS) {
341 PrivilegeDb::getInstance().RollbackTransaction();
342 LogError("Error while processing request on master: " << ret);
346 CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
350 PrivilegeDb::getInstance().CommitTransaction();
351 LogDebug("Application installation commited to database");
352 } catch (const PrivilegeDb::Exception::IOError &e) {
353 LogError("Cannot access application database: " << e.DumpToString());
354 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
355 } catch (const PrivilegeDb::Exception::InternalError &e) {
356 PrivilegeDb::getInstance().RollbackTransaction();
357 LogError("Error while saving application info to database: " << e.DumpToString());
358 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
359 } catch (const CynaraException::Base &e) {
360 PrivilegeDb::getInstance().RollbackTransaction();
361 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
362 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
363 } catch (const SmackException::InvalidLabel &e) {
364 PrivilegeDb::getInstance().RollbackTransaction();
365 LogError("Error while generating Smack labels: " << e.DumpToString());
366 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
367 } catch (const std::bad_alloc &e) {
368 PrivilegeDb::getInstance().RollbackTransaction();
369 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
370 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
375 SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
378 for (const auto &appPath : req.appPaths) {
379 const std::string &path = appPath.first;
380 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
381 SmackLabels::setupPath(req.appId, path, pathType, zoneId);
385 LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
386 << req.pkgId << ". Applications in package: " << pkgContents.size());
387 int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
388 if (ret != SECURITY_MANAGER_API_SUCCESS) {
389 LogError("Master failed to apply package-specific smack rules: " << ret);
393 LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
394 << req.pkgId << ". Applications in package: " << pkgContents.size());
395 SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
397 } catch (const SmackException::Base &e) {
398 LogError("Error while applying Smack policy for application: " << e.DumpToString());
399 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
400 } catch (const SecurityManager::Exception &e) {
401 LogError("Security Manager exception: " << e.DumpToString());
402 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
403 }catch (const std::bad_alloc &e) {
404 LogError("Memory allocation error: " << e.what());
405 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
408 return SECURITY_MANAGER_API_SUCCESS;
411 int appUninstall(const std::string &appId, uid_t uid, bool isSlave)
414 std::string smackLabel;
415 std::vector<std::string> pkgContents;
416 bool appExists = true;
417 bool removePkg = false;
419 checkGlobalUser(uid, uidstr);
423 if (!getZoneId(zoneId)) {
424 LogError("Failed to get Zone ID.");
425 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
430 std::vector<std::string> oldAppPrivileges;
432 PrivilegeDb::getInstance().BeginTransaction();
433 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
434 LogWarning("Application " << appId <<
435 " not found in database while uninstalling");
436 PrivilegeDb::getInstance().RollbackTransaction();
439 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
440 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
441 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
443 /* Before we remove the app from the database, let's fetch all apps in the package
444 that this app belongs to, this will allow us to remove all rules withing the
445 package that the app appears in */
446 PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
447 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
448 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
449 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
452 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
453 std::vector<std::string>());
454 if (ret != SECURITY_MANAGER_API_SUCCESS) {
455 PrivilegeDb::getInstance().RollbackTransaction();
456 LogError("Error while processing request on master: " << ret);
460 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
461 std::vector<std::string>());
464 PrivilegeDb::getInstance().CommitTransaction();
465 LogDebug("Application uninstallation commited to database");
467 } catch (const PrivilegeDb::Exception::IOError &e) {
468 LogError("Cannot access application database: " << e.DumpToString());
469 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
470 } catch (const PrivilegeDb::Exception::InternalError &e) {
471 PrivilegeDb::getInstance().RollbackTransaction();
472 LogError("Error while removing application info from database: " << e.DumpToString());
473 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
474 } catch (const CynaraException::Base &e) {
475 PrivilegeDb::getInstance().RollbackTransaction();
476 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
477 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
478 } catch (const SmackException::InvalidLabel &e) {
479 PrivilegeDb::getInstance().RollbackTransaction();
480 LogError("Error while generating Smack labels: " << e.DumpToString());
481 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
482 } catch (const std::bad_alloc &e) {
483 PrivilegeDb::getInstance().RollbackTransaction();
484 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
485 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
491 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
493 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
494 if (ret != SECURITY_MANAGER_API_SUCCESS) {
495 LogError("Error while processing uninstall request on master: " << ret);
500 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
501 SmackRules::uninstallPackageRules(pkgId);
504 LogDebug ("Removing smack rules for deleted appId " << appId);
505 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
507 } catch (const SmackException::Base &e) {
508 LogError("Error while removing Smack rules for application: " << e.DumpToString());
509 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
510 } catch (const SecurityManager::Exception &e) {
511 LogError("Security Manager error: " << e.DumpToString());
512 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
513 } catch (const std::bad_alloc &e) {
514 LogError("Memory allocation error: " << e.what());
515 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
519 return SECURITY_MANAGER_API_SUCCESS;
522 int getPkgId(const std::string &appId, std::string &pkgId)
524 LogDebug("appId: " << appId);
527 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
528 LogWarning("Application " << appId << " not found in database");
529 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
531 LogDebug("pkgId: " << pkgId);
533 } catch (const PrivilegeDb::Exception::Base &e) {
534 LogError("Error while getting pkgId from database: " << e.DumpToString());
535 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
538 return SECURITY_MANAGER_API_SUCCESS;
541 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
542 std::unordered_set<gid_t> &gids)
544 // FIXME Temporary solution, see below
547 if (!getZoneId(zoneId)) {
548 LogError("Failed to get Zone ID.");
549 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
555 std::string smackLabel;
556 std::string uidStr = std::to_string(uid);
557 std::string pidStr = std::to_string(pid);
559 LogDebug("appId: " << appId);
561 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
562 LogWarning("Application " << appId << " not found in database");
563 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
565 LogDebug("pkgId: " << pkgId);
567 // FIXME getAppGroups should work without generating zone-specific labels when
568 // Smack Namespaces will work
569 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
570 LogDebug("smack label: " << smackLabel);
572 std::vector<std::string> privileges;
573 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
574 /*there is also a need of checking, if privilege is granted to all users*/
575 size_t tmp = privileges.size();
576 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
577 /*privileges needs to be sorted and with no duplications - for cynara sake*/
578 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
579 privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
581 for (const auto &privilege : privileges) {
582 std::vector<std::string> gidsTmp;
583 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
584 if (!gidsTmp.empty()) {
585 LogDebug("Considering privilege " << privilege << " with " <<
586 gidsTmp.size() << " groups assigned");
587 // TODO: create method in Cynara class for fetching all privileges of an application
588 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
589 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
590 struct group *grp = getgrnam(group.c_str());
592 LogError("No such group: " << group.c_str());
595 gids.insert(grp->gr_gid);
597 LogDebug("Cynara allowed, adding groups");
599 LogDebug("Cynara denied, not adding groups");
602 } catch (const PrivilegeDb::Exception::Base &e) {
603 LogError("Database error: " << e.DumpToString());
604 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
605 } catch (const CynaraException::Base &e) {
606 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
607 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
608 } catch (const SmackException::InvalidLabel &e) {
609 LogError("Error while generating Smack labels: " << e.DumpToString());
610 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
611 } catch (const std::bad_alloc &e) {
612 LogError("Memory allocation failed: " << e.what());
613 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
616 return SECURITY_MANAGER_API_SUCCESS;
619 int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
622 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
625 int ret = MasterReq::CynaraUserInit(uidAdded,
626 static_cast<security_manager_user_type>(userType));
627 if (ret != SECURITY_MANAGER_API_SUCCESS) {
628 LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
633 CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
634 } catch (CynaraException::InvalidParam &e) {
635 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
639 return SECURITY_MANAGER_API_SUCCESS;
642 int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
644 int ret = SECURITY_MANAGER_API_SUCCESS;
646 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
648 /*Uninstall all user apps*/
649 std::vector<std::string> userApps;
651 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
652 } catch (const PrivilegeDb::Exception::Base &e) {
653 LogError("Error while getting user apps from database: " << e.DumpToString());
654 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
657 for (auto &app: userApps) {
658 if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
659 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
660 we do not have anything special to do about that matter - user will be deleted anyway.*/
661 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
666 int ret = MasterReq::CynaraUserRemove(uidDeleted);
668 LogError("Master failed to delete user " << uidDeleted);
672 CynaraAdmin::getInstance().UserRemove(uidDeleted);
678 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
684 } isAdmin = NOT_CHECKED;
687 std::string uidStr = std::to_string(uid);
688 std::string pidStr = std::to_string(pid);
690 if (policyEntries.size() == 0) {
691 LogError("Validation failed: policy update request is empty");
692 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
695 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
696 LogError("Not enough permission to call: " << __FUNCTION__);
697 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
700 std::vector<CynaraAdminPolicy> validatedPolicies;
702 for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
703 bool forAdmin = false;
704 CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
705 int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
707 if (forAdmin && (isAdmin == NOT_CHECKED)) {
708 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
711 if (ret == SECURITY_MANAGER_API_SUCCESS) {
713 || (forAdmin && (isAdmin == IS_ADMIN))) {
714 validatedPolicies.push_back(std::move(cyap));
716 LogError("Not enough privilege to enforce admin policy");
717 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
725 CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
727 } catch (const CynaraException::Base &e) {
728 LogError("Error while updating Cynara rules: " << e.DumpToString());
729 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
730 } catch (const std::bad_alloc &e) {
731 LogError("Memory allocation error while updating Cynara rules: " << e.what());
732 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
735 return SECURITY_MANAGER_API_SUCCESS;
738 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
739 const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
742 std::string uidStr = std::to_string(uid);
743 std::string pidStr = std::to_string(pid);
745 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
746 LogError("Not enough permission to call: " << __FUNCTION__);
747 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
750 LogDebug("Filter is: C: " << filter.appId
751 << ", U: " << filter.user
752 << ", P: " << filter.privilege
753 << ", current: " << filter.currentLevel
754 << ", max: " << filter.maxLevel
757 std::vector<CynaraAdminPolicy> listOfPolicies;
759 //convert appId to smack label
760 std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
761 std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
762 std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
764 LogDebug("App: " << filter.appId << ", Label: " << appLabel);
767 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
768 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
769 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
772 //Fetch privileges from ADMIN bucket
773 CynaraAdmin::getInstance().ListPolicies(
774 CynaraAdmin::Buckets.at(Bucket::ADMIN),
780 LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
782 if (uidStr.compare(user)) {
783 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
784 LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
788 //Fetch privileges from PRIVACY_MANAGER bucket
789 CynaraAdmin::getInstance().ListPolicies(
790 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
796 LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
799 for (const auto &policy : listOfPolicies) {
800 //ignore "jump to bucket" entries
801 if (policy.result == CYNARA_ADMIN_BUCKET)
806 pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
807 pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
808 pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
809 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
812 // All policy entries in PRIVACY_MANAGER should be fully-qualified
813 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
814 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
815 policy.client, policy.user, policy.privilege));
817 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
818 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
823 "[policy_entry] app: " << pe.appId
824 << " user: " << pe.user
825 << " privilege: " << pe.privilege
826 << " current: " << pe.currentLevel
827 << " max: " << pe.maxLevel
830 policyEntries.push_back(pe);
833 } catch (const CynaraException::Base &e) {
834 LogError("Error while listing Cynara rules: " << e.DumpToString());
835 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
836 } catch (const SmackException::InvalidLabel &e) {
837 LogError("Error while generating Smack labels: " << e.DumpToString());
838 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
839 } catch (const std::bad_alloc &e) {
840 LogError("Memory allocation error while listing Cynara rules: " << e.what());
841 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
845 return SECURITY_MANAGER_API_SUCCESS;
848 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
851 std::string uidStr = std::to_string(uid);
852 std::string pidStr = std::to_string(pid);
854 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
855 LogWarning("Not enough permission to call: " << __FUNCTION__);
856 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
859 LogDebug("Filter is: C: " << filter.appId
860 << ", U: " << filter.user
861 << ", P: " << filter.privilege
862 << ", current: " << filter.currentLevel
863 << ", max: " << filter.maxLevel
866 std::vector<uid_t> listOfUsers;
868 if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
869 LogDebug("User is privileged");
870 if (filter.user.compare(SECURITY_MANAGER_ANY)) {
871 LogDebug("Limitting Cynara query to user: " << filter.user);
873 listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
874 } catch (std::invalid_argument &e) {
875 LogError("Invalid UID: " << e.what());
878 CynaraAdmin::getInstance().ListUsers(listOfUsers);
880 LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
881 LogDebug("Fetching personal policy for user: " << uid);
882 listOfUsers.push_back(uid);
884 LogDebug("Fetching policy for " << listOfUsers.size() << " users");
886 for (const uid_t &uid : listOfUsers) {
887 LogDebug("User: " << uid);
888 std::string userStr = std::to_string(uid);
889 std::vector<std::string> listOfApps;
891 if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
892 LogDebug("Limitting Cynara query to app: " << filter.appId);
893 listOfApps.push_back(filter.appId);
895 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
896 LogDebug("Found apps: " << listOfApps.size());
899 for (const std::string &appId : listOfApps) {
900 LogDebug("App: " << appId);
901 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
902 std::vector<std::string> listOfPrivileges;
904 // FIXME: also fetch privileges of global applications
905 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
907 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
908 LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
909 // FIXME: this filtering should be already performed by method fetching the privileges
910 if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
911 filter.privilege) == listOfPrivileges.end()) {
912 LogDebug("Application " << appId <<
913 " doesn't have the filteres privilege " << filter.privilege);
916 listOfPrivileges.clear();
917 listOfPrivileges.push_back(filter.privilege);
920 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
922 for (const std::string &privilege : listOfPrivileges) {
923 LogDebug("Privilege: " << privilege);
928 pe.privilege = privilege;
930 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
931 CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
932 smackLabelForApp, userStr, privilege));
934 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
935 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
936 smackLabelForApp, userStr, privilege));
939 "[policy_entry] app: " << pe.appId
940 << " user: " << pe.user
941 << " privilege: " << pe.privilege
942 << " current: " << pe.currentLevel
943 << " max: " << pe.maxLevel
946 policyEntries.push_back(pe);
951 } catch (const CynaraException::Base &e) {
952 LogError("Error while listing Cynara rules: " << e.DumpToString());
953 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
954 } catch (const SmackException::InvalidLabel &e) {
955 LogError("Error while generating Smack labels: " << e.DumpToString());
956 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
957 } catch (const std::bad_alloc &e) {
958 LogError("Memory allocation error while listing Cynara rules: " << e.what());
959 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
962 return SECURITY_MANAGER_API_SUCCESS;
965 int policyGetDesc(std::vector<std::string> &levels)
967 int ret = SECURITY_MANAGER_API_SUCCESS;
970 CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
971 } catch (const CynaraException::OutOfMemory &e) {
972 LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
973 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
974 } catch (const CynaraException::InvalidParam &e) {
975 LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
976 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
977 } catch (const CynaraException::ServiceNotAvailable &e) {
978 LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
979 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
980 } catch (const CynaraException::Base &e) {
981 LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
982 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
988 int getPrivilegesMappings(const std::string &version_from,
989 const std::string &version_to,
990 const std::vector<std::string> &privileges,
991 std::vector<std::string> &mappings)
995 std::string finalVersionTo;
996 if (version_to.empty()) {
997 finalVersionTo = Config::PRIVILEGE_VERSION;
999 finalVersionTo = version_to;
1002 PrivilegeDb::getInstance().BeginTransaction();
1003 if (privileges.size() == 0) {
1004 PrivilegeDb::getInstance().GetDefaultMapping(version_from, finalVersionTo, mappings);
1005 } else if ( privileges.size() == 1) {
1006 PrivilegeDb::getInstance().GetPrivilegeMappings(version_from, finalVersionTo,
1007 privileges.front(), mappings);
1009 PrivilegeDb::getInstance().GetPrivilegesMappings(version_from, finalVersionTo,
1010 privileges, mappings);
1012 PrivilegeDb::getInstance().CommitTransaction();
1013 return SECURITY_MANAGER_API_SUCCESS;
1014 } catch (const PrivilegeDb::Exception::IOError &e) {
1015 LogError("Cannot access application database: " << e.DumpToString());
1016 errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1017 } catch (const PrivilegeDb::Exception::InternalError &e) {
1018 LogError("Error while getting privilege mapping from database: " << e.DumpToString());
1019 errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1020 } catch (const std::bad_alloc &e) {
1021 LogError("Memory allocation failed: " << e.what());
1022 errorRet = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
1023 } catch (const std::exception &e) {
1024 LogError("Some exception thrown : " << e.what());
1025 errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1027 LogError("Unknown exception thrown");
1028 errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1030 PrivilegeDb::getInstance().RollbackTransaction();
1034 int policyGetGroups(std::vector<std::string> &groups) {
1035 int ret = SECURITY_MANAGER_API_SUCCESS;
1038 PrivilegeDb::getInstance().GetGroups(groups);
1039 } catch (const PrivilegeDb::Exception::Base &e) {
1040 LogError("Error while getting groups from database: " << e.DumpToString());
1041 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1047 } /* namespace ServiceImpl */
1048 } /* namespace SecurityManager */