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
30 #include <sys/socket.h>
35 #include <dpl/log/log.h>
36 #include <tzplatform_config.h>
38 #include "protocols.h"
39 #include "privilege_db.h"
41 #include "smack-rules.h"
42 #include "smack-labels.h"
43 #include "security-manager.h"
44 #include "zone-utils.h"
46 #include "service_impl.h"
47 #include "master-req.h"
49 namespace SecurityManager {
50 namespace ServiceImpl {
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 static uid_t getGlobalUserId(void)
137 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
142 * Unifies user data of apps installed for all users
143 * @param uid peer's uid - may be changed during process
144 * @param cynaraUserStr string to which cynara user parameter will be put
146 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
148 static uid_t globaluid = getGlobalUserId();
149 if (uid == 0 || uid == globaluid) {
151 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
153 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
156 static inline bool isSubDir(const char *parent, const char *subdir)
158 while (*parent && *subdir)
159 if (*parent++ != *subdir++)
162 return (*subdir == '/');
165 bool getPeerID(int sock, uid_t &uid, pid_t &pid)
168 socklen_t len = sizeof(cr);
170 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
179 static bool getUserAppDir(const uid_t &uid, std::string &userAppDir)
181 struct tzplatform_context *tz_ctx = nullptr;
183 if (tzplatform_context_create(&tz_ctx))
186 if (tzplatform_context_set_user(tz_ctx, uid)) {
187 tzplatform_context_destroy(tz_ctx);
192 enum tzplatform_variable id =
193 (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
194 const char *appDir = tzplatform_context_getenv(tz_ctx, id);
196 tzplatform_context_destroy(tz_ctx);
203 tzplatform_context_destroy(tz_ctx);
209 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
211 std::string userHome;
212 std::string userAppDir;
213 std::stringstream correctPath;
215 if (uid != getGlobalUserId())
216 LogDebug("Installation type: single user");
218 LogDebug("Installation type: global installation");
220 if (!getUserAppDir(uid, userAppDir)) {
221 LogError("Failed getting app dir for user uid: " << uid);
225 appPath = userAppDir;
227 correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
228 LogDebug("correctPath: " << correctPath.str());
230 for (const auto &appPath : req.appPaths) {
231 std::unique_ptr<char, std::function<void(void*)>> real_path(
232 realpath(appPath.first.c_str(), NULL), free);
233 if (!real_path.get()) {
234 LogError("realpath failed with '" << appPath.first.c_str()
235 << "' as parameter: " << strerror(errno));
238 LogDebug("Requested path is '" << appPath.first.c_str()
239 << "'. User's APPS_DIR is '" << userAppDir << "'");
240 if (!isSubDir(userAppDir.c_str(), real_path.get())) {
241 LogWarning("User's apps may have registered folders only in user's APPS_DIR");
245 if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
246 LogWarning("Installation is outside correct path: " << correctPath.str());
249 isCorrectPath = true;
251 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
252 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
253 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
260 static inline bool getZoneId(std::string &zoneId)
262 if (!getZoneIdFromPid(getpid(), zoneId)) {
263 LogError("Failed to get zone ID from current PID");
267 // This function should be called under slave mode only - assumes, that we work inside zone
268 if (zoneId == ZONE_HOST) {
269 LogError("We should not run in host - refusing request");
276 int appInstall(const app_inst_req &req, uid_t uid, bool isSlave)
278 std::vector<std::string> addedPermissions;
279 std::vector<std::string> removedPermissions;
280 std::vector<std::string> pkgContents;
282 bool isCorrectPath = false;
284 std::string appLabel;
285 std::string pkgLabel;
289 if (!getZoneId(zoneId)) {
290 LogError("Failed to get Zone ID.");
291 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
296 if (uid != req.uid) {
297 LogError("User " << uid <<
298 " is denied to install application for user " << req.uid);
299 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
305 checkGlobalUser(uid, uidstr);
307 if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
308 LogError("Request from uid " << uid << " for app installation denied");
309 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
313 std::vector<std::string> oldAppPrivileges;
315 appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
316 /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
317 pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
318 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
319 << ", uidstr " << uidstr
320 << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
322 PrivilegeDb::getInstance().BeginTransaction();
324 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
325 if (ret == true && pkg != req.pkgId) {
326 LogError("Application already installed with different package id");
327 PrivilegeDb::getInstance().RollbackTransaction();
328 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
330 PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
331 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
332 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
333 /* Get all application ids in the package to generate rules withing the package */
334 PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
337 int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
339 if (ret != SECURITY_MANAGER_API_SUCCESS) {
340 PrivilegeDb::getInstance().RollbackTransaction();
341 LogError("Error while processing request on master: " << ret);
345 CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
349 PrivilegeDb::getInstance().CommitTransaction();
350 LogDebug("Application installation commited to database");
351 } catch (const PrivilegeDb::Exception::IOError &e) {
352 LogError("Cannot access application database: " << e.DumpToString());
353 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
354 } catch (const PrivilegeDb::Exception::InternalError &e) {
355 PrivilegeDb::getInstance().RollbackTransaction();
356 LogError("Error while saving application info to database: " << e.DumpToString());
357 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
358 } catch (const CynaraException::Base &e) {
359 PrivilegeDb::getInstance().RollbackTransaction();
360 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
361 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
362 } catch (const SmackException::InvalidLabel &e) {
363 PrivilegeDb::getInstance().RollbackTransaction();
364 LogError("Error while generating Smack labels: " << e.DumpToString());
365 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
366 } catch (const std::bad_alloc &e) {
367 PrivilegeDb::getInstance().RollbackTransaction();
368 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
369 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
374 SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
377 for (const auto &appPath : req.appPaths) {
378 const std::string &path = appPath.first;
379 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
380 SmackLabels::setupPath(req.appId, path, pathType, zoneId);
384 LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
385 << req.pkgId << ". Applications in package: " << pkgContents.size());
386 int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
387 if (ret != SECURITY_MANAGER_API_SUCCESS) {
388 LogError("Master failed to apply package-specific smack rules: " << ret);
392 LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
393 << req.pkgId << ". Applications in package: " << pkgContents.size());
394 SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
396 } catch (const SmackException::Base &e) {
397 LogError("Error while applying Smack policy for application: " << e.DumpToString());
398 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
399 } catch (const SecurityManager::Exception &e) {
400 LogError("Security Manager exception: " << e.DumpToString());
401 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
402 }catch (const std::bad_alloc &e) {
403 LogError("Memory allocation error: " << e.what());
404 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
407 return SECURITY_MANAGER_API_SUCCESS;
410 int appUninstall(const std::string &appId, uid_t uid, bool isSlave)
413 std::string smackLabel;
414 std::vector<std::string> pkgContents;
415 bool appExists = true;
416 bool removePkg = false;
418 checkGlobalUser(uid, uidstr);
422 if (!getZoneId(zoneId)) {
423 LogError("Failed to get Zone ID.");
424 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
429 std::vector<std::string> oldAppPrivileges;
431 PrivilegeDb::getInstance().BeginTransaction();
432 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
433 LogWarning("Application " << appId <<
434 " not found in database while uninstalling");
435 PrivilegeDb::getInstance().RollbackTransaction();
438 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
439 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
440 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
442 /* Before we remove the app from the database, let's fetch all apps in the package
443 that this app belongs to, this will allow us to remove all rules withing the
444 package that the app appears in */
445 PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
446 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
447 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
448 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
451 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
452 std::vector<std::string>());
453 if (ret != SECURITY_MANAGER_API_SUCCESS) {
454 PrivilegeDb::getInstance().RollbackTransaction();
455 LogError("Error while processing request on master: " << ret);
459 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
460 std::vector<std::string>());
463 PrivilegeDb::getInstance().CommitTransaction();
464 LogDebug("Application uninstallation commited to database");
466 } catch (const PrivilegeDb::Exception::IOError &e) {
467 LogError("Cannot access application database: " << e.DumpToString());
468 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
469 } catch (const PrivilegeDb::Exception::InternalError &e) {
470 PrivilegeDb::getInstance().RollbackTransaction();
471 LogError("Error while removing application info from database: " << e.DumpToString());
472 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
473 } catch (const CynaraException::Base &e) {
474 PrivilegeDb::getInstance().RollbackTransaction();
475 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
476 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
477 } catch (const SmackException::InvalidLabel &e) {
478 PrivilegeDb::getInstance().RollbackTransaction();
479 LogError("Error while generating Smack labels: " << e.DumpToString());
480 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
481 } catch (const std::bad_alloc &e) {
482 PrivilegeDb::getInstance().RollbackTransaction();
483 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
484 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
490 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
492 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
493 if (ret != SECURITY_MANAGER_API_SUCCESS) {
494 LogError("Error while processing uninstall request on master: " << ret);
499 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
500 SmackRules::uninstallPackageRules(pkgId);
503 LogDebug ("Removing smack rules for deleted appId " << appId);
504 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
506 } catch (const SmackException::Base &e) {
507 LogError("Error while removing Smack rules for application: " << e.DumpToString());
508 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
509 } catch (const SecurityManager::Exception &e) {
510 LogError("Security Manager error: " << e.DumpToString());
511 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
512 } catch (const std::bad_alloc &e) {
513 LogError("Memory allocation error: " << e.what());
514 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
518 return SECURITY_MANAGER_API_SUCCESS;
521 int getPkgId(const std::string &appId, std::string &pkgId)
523 LogDebug("appId: " << appId);
526 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
527 LogWarning("Application " << appId << " not found in database");
528 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
530 LogDebug("pkgId: " << pkgId);
532 } catch (const PrivilegeDb::Exception::Base &e) {
533 LogError("Error while getting pkgId from database: " << e.DumpToString());
534 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
537 return SECURITY_MANAGER_API_SUCCESS;
540 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
541 std::unordered_set<gid_t> &gids)
543 // FIXME Temporary solution, see below
546 if (!getZoneId(zoneId)) {
547 LogError("Failed to get Zone ID.");
548 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
554 std::string smackLabel;
555 std::string uidStr = std::to_string(uid);
556 std::string pidStr = std::to_string(pid);
558 LogDebug("appId: " << appId);
560 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
561 LogWarning("Application " << appId << " not found in database");
562 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
564 LogDebug("pkgId: " << pkgId);
566 // FIXME getAppGroups should work without generating zone-specific labels when
567 // Smack Namespaces will work
568 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
569 LogDebug("smack label: " << smackLabel);
571 std::vector<std::string> privileges;
572 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
573 /*there is also a need of checking, if privilege is granted to all users*/
574 size_t tmp = privileges.size();
575 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
576 /*privileges needs to be sorted and with no duplications - for cynara sake*/
577 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
578 privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
580 for (const auto &privilege : privileges) {
581 std::vector<std::string> gidsTmp;
582 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
583 if (!gidsTmp.empty()) {
584 LogDebug("Considering privilege " << privilege << " with " <<
585 gidsTmp.size() << " groups assigned");
586 // TODO: create method in Cynara class for fetching all privileges of an application
587 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
588 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
589 struct group *grp = getgrnam(group.c_str());
591 LogError("No such group: " << group.c_str());
594 gids.insert(grp->gr_gid);
596 LogDebug("Cynara allowed, adding groups");
598 LogDebug("Cynara denied, not adding groups");
601 } catch (const PrivilegeDb::Exception::Base &e) {
602 LogError("Database error: " << e.DumpToString());
603 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
604 } catch (const CynaraException::Base &e) {
605 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
606 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
607 } catch (const SmackException::InvalidLabel &e) {
608 LogError("Error while generating Smack labels: " << e.DumpToString());
609 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
610 } catch (const std::bad_alloc &e) {
611 LogError("Memory allocation failed: " << e.what());
612 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
615 return SECURITY_MANAGER_API_SUCCESS;
618 int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
621 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
624 int ret = MasterReq::CynaraUserInit(uidAdded,
625 static_cast<security_manager_user_type>(userType));
626 if (ret != SECURITY_MANAGER_API_SUCCESS) {
627 LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
632 CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
633 } catch (CynaraException::InvalidParam &e) {
634 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
638 return SECURITY_MANAGER_API_SUCCESS;
641 int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
643 int ret = SECURITY_MANAGER_API_SUCCESS;
645 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
647 /*Uninstall all user apps*/
648 std::vector<std::string> userApps;
650 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
651 } catch (const PrivilegeDb::Exception::Base &e) {
652 LogError("Error while getting user apps from database: " << e.DumpToString());
653 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
656 for (auto &app: userApps) {
657 if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
658 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
659 we do not have anything special to do about that matter - user will be deleted anyway.*/
660 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
665 int ret = MasterReq::CynaraUserRemove(uidDeleted);
667 LogError("Master failed to delete user " << uidDeleted);
671 CynaraAdmin::getInstance().UserRemove(uidDeleted);
677 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
683 } isAdmin = NOT_CHECKED;
686 std::string uidStr = std::to_string(uid);
687 std::string pidStr = std::to_string(pid);
689 if (policyEntries.size() == 0) {
690 LogError("Validation failed: policy update request is empty");
691 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
694 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
695 LogError("Not enough permission to call: " << __FUNCTION__);
696 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
699 std::vector<CynaraAdminPolicy> validatedPolicies;
701 for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
702 bool forAdmin = false;
703 CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
704 int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
706 if (forAdmin && (isAdmin == NOT_CHECKED)) {
707 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
710 if (ret == SECURITY_MANAGER_API_SUCCESS) {
712 || (forAdmin && (isAdmin == IS_ADMIN))) {
713 validatedPolicies.push_back(std::move(cyap));
715 LogError("Not enough privilege to enforce admin policy");
716 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
724 CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
726 } catch (const CynaraException::Base &e) {
727 LogError("Error while updating Cynara rules: " << e.DumpToString());
728 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
729 } catch (const std::bad_alloc &e) {
730 LogError("Memory allocation error while updating Cynara rules: " << e.what());
731 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
734 return SECURITY_MANAGER_API_SUCCESS;
737 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
738 const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
741 std::string uidStr = std::to_string(uid);
742 std::string pidStr = std::to_string(pid);
744 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
745 LogError("Not enough permission to call: " << __FUNCTION__);
746 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
749 LogDebug("Filter is: C: " << filter.appId
750 << ", U: " << filter.user
751 << ", P: " << filter.privilege
752 << ", current: " << filter.currentLevel
753 << ", max: " << filter.maxLevel
756 std::vector<CynaraAdminPolicy> listOfPolicies;
758 //convert appId to smack label
759 std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
760 std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
761 std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
763 LogDebug("App: " << filter.appId << ", Label: " << appLabel);
766 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
767 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
768 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
771 //Fetch privileges from ADMIN bucket
772 CynaraAdmin::getInstance().ListPolicies(
773 CynaraAdmin::Buckets.at(Bucket::ADMIN),
779 LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
781 if (uidStr.compare(user)) {
782 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
783 LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
787 //Fetch privileges from PRIVACY_MANAGER bucket
788 CynaraAdmin::getInstance().ListPolicies(
789 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
795 LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
798 for (const auto &policy : listOfPolicies) {
799 //ignore "jump to bucket" entries
800 if (policy.result == CYNARA_ADMIN_BUCKET)
805 pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
806 pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
807 pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
808 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
811 // All policy entries in PRIVACY_MANAGER should be fully-qualified
812 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
813 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
814 policy.client, policy.user, policy.privilege));
816 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
817 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
822 "[policy_entry] app: " << pe.appId
823 << " user: " << pe.user
824 << " privilege: " << pe.privilege
825 << " current: " << pe.currentLevel
826 << " max: " << pe.maxLevel
829 policyEntries.push_back(pe);
832 } catch (const CynaraException::Base &e) {
833 LogError("Error while listing Cynara rules: " << e.DumpToString());
834 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
835 } catch (const SmackException::InvalidLabel &e) {
836 LogError("Error while generating Smack labels: " << e.DumpToString());
837 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
838 } catch (const std::bad_alloc &e) {
839 LogError("Memory allocation error while listing Cynara rules: " << e.what());
840 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
844 return SECURITY_MANAGER_API_SUCCESS;
847 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
850 std::string uidStr = std::to_string(uid);
851 std::string pidStr = std::to_string(pid);
853 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
854 LogWarning("Not enough permission to call: " << __FUNCTION__);
855 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
858 LogDebug("Filter is: C: " << filter.appId
859 << ", U: " << filter.user
860 << ", P: " << filter.privilege
861 << ", current: " << filter.currentLevel
862 << ", max: " << filter.maxLevel
865 std::vector<uid_t> listOfUsers;
867 if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
868 LogDebug("User is privileged");
869 if (filter.user.compare(SECURITY_MANAGER_ANY)) {
870 LogDebug("Limitting Cynara query to user: " << filter.user);
872 listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
873 } catch (std::invalid_argument &e) {
874 LogError("Invalid UID: " << e.what());
877 CynaraAdmin::getInstance().ListUsers(listOfUsers);
879 LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
880 LogDebug("Fetching personal policy for user: " << uid);
881 listOfUsers.push_back(uid);
883 LogDebug("Fetching policy for " << listOfUsers.size() << " users");
885 for (const uid_t &uid : listOfUsers) {
886 LogDebug("User: " << uid);
887 std::string userStr = std::to_string(uid);
888 std::vector<std::string> listOfApps;
890 if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
891 LogDebug("Limitting Cynara query to app: " << filter.appId);
892 listOfApps.push_back(filter.appId);
894 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
895 LogDebug("Found apps: " << listOfApps.size());
898 for (const std::string &appId : listOfApps) {
899 LogDebug("App: " << appId);
900 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
901 std::vector<std::string> listOfPrivileges;
903 // FIXME: also fetch privileges of global applications
904 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
906 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
907 LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
908 // FIXME: this filtering should be already performed by method fetching the privileges
909 if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
910 filter.privilege) == listOfPrivileges.end()) {
911 LogDebug("Application " << appId <<
912 " doesn't have the filteres privilege " << filter.privilege);
915 listOfPrivileges.clear();
916 listOfPrivileges.push_back(filter.privilege);
919 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
921 for (const std::string &privilege : listOfPrivileges) {
922 LogDebug("Privilege: " << privilege);
927 pe.privilege = privilege;
929 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
930 CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
931 smackLabelForApp, userStr, privilege));
933 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
934 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
935 smackLabelForApp, userStr, privilege));
938 "[policy_entry] app: " << pe.appId
939 << " user: " << pe.user
940 << " privilege: " << pe.privilege
941 << " current: " << pe.currentLevel
942 << " max: " << pe.maxLevel
945 policyEntries.push_back(pe);
950 } catch (const CynaraException::Base &e) {
951 LogError("Error while listing Cynara rules: " << e.DumpToString());
952 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
953 } catch (const SmackException::InvalidLabel &e) {
954 LogError("Error while generating Smack labels: " << e.DumpToString());
955 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
956 } catch (const std::bad_alloc &e) {
957 LogError("Memory allocation error while listing Cynara rules: " << e.what());
958 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
961 return SECURITY_MANAGER_API_SUCCESS;
964 int policyGetDesc(std::vector<std::string> &levels)
966 int ret = SECURITY_MANAGER_API_SUCCESS;
969 CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
970 } catch (const CynaraException::OutOfMemory &e) {
971 LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
972 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
973 } catch (const CynaraException::InvalidParam &e) {
974 LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
975 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
976 } catch (const CynaraException::ServiceNotAvailable &e) {
977 LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
978 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
979 } catch (const CynaraException::Base &e) {
980 LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
981 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
987 } /* namespace ServiceImpl */
988 } /* namespace SecurityManager */