* @author Michal Witanowski <m.witanowski@samsung.com>
* @author Jacek Bukarewicz <j.bukarewicz@samsung.com>
* @author Rafal Krypa <r.krypa@samsung.com>
+ * @author Krzysztof Sasiak <k.sasiak@samsung.com>
* @brief Implementation of the service methods
*/
#include "cynara.h"
#include "smack-rules.h"
#include "smack-labels.h"
+#include "security-manager.h"
#include "service_impl.h"
namespace SecurityManager {
namespace ServiceImpl {
+static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
+static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
+
+namespace {
+
+static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
+{
+ LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
+ LogDebug("[policy_entry] app: " << policyEntry.appId
+ << " user: " << policyEntry.user
+ << " privilege: " << policyEntry.privilege
+ << " current: " << policyEntry.currentLevel
+ << " max: " << policyEntry.maxLevel);
+ //automagically fill missing fields:
+ if (policyEntry.user.empty()) {
+ policyEntry.user = uidStr;
+ };
+
+ std::string client;
+ int level;
+
+ if (policyEntry.currentLevel.empty()) { //for admin
+ if (policyEntry.appId.empty()
+ || policyEntry.privilege.empty()) {
+ LogError("Bad admin update request");
+ return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+ };
+
+ if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
+ level = CYNARA_ADMIN_DELETE;
+ } else {
+ try {
+ level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
+ } catch (const std::out_of_range& e) {
+ LogError("policy max level cannot be: " << policyEntry.maxLevel);
+ return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
+ };
+ };
+ forAdmin = true;
+
+ } else if (policyEntry.maxLevel.empty()) { //for self
+ if (policyEntry.user.compare(uidStr)
+ || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
+ || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
+ || policyEntry.appId.empty()
+ || policyEntry.privilege.empty()) {
+ LogError("Bad privacy manager update request");
+ return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+ };
+
+ if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
+ level = CYNARA_ADMIN_DELETE;
+ } else {
+ try {
+ level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
+ } catch (const std::out_of_range& e) {
+ LogError("policy current level cannot be: " << policyEntry.currentLevel);
+ return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
+ };
+ };
+ forAdmin = false;
+
+ } else { //neither => bad request
+ return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+ };
+
+ if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
+ policyEntry.user = CYNARA_ADMIN_WILDCARD;
+ if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
+ policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
+ if (policyEntry.appId.compare(SECURITY_MANAGER_ANY))
+ generateAppLabel(policyEntry.appId, client);
+ else
+ client = CYNARA_ADMIN_WILDCARD;
+
+ cyap = std::move(CynaraAdminPolicy(
+ client,
+ policyEntry.user,
+ policyEntry.privilege,
+ level,
+ (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
+
+ LogDebug("Policy update request authenticated and validated successfully");
+ return SECURITY_MANAGER_API_SUCCESS;
+}
+} // end of anonymous namespace
+
static uid_t getGlobalUserId(void)
{
static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
/* Get all application ids in the package to generate rules withing the package */
PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
- CynaraAdmin::UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
+ CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
req.privileges);
PrivilegeDb::getInstance().CommitTransaction();
LogDebug("Application installation commited to database");
PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
- CynaraAdmin::UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
+ CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
std::vector<std::string>());
PrivilegeDb::getInstance().CommitTransaction();
LogDebug("Application uninstallation commited to database");
if (uid != 0)
return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
- switch (userType) {
- case SM_USER_TYPE_SYSTEM:
- case SM_USER_TYPE_ADMIN:
- case SM_USER_TYPE_GUEST:
- case SM_USER_TYPE_NORMAL:
- break;
- default:
+ try {
+ CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
+ } catch (CynaraException::InvalidParam &e) {
return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
}
-
- //TODO add policy information to cynara regarding user default privileges based on user_type
- (void) uidAdded;
- (void) userType;
-
return SECURITY_MANAGER_API_SUCCESS;
}
if (uid != 0)
return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
- //TODO remove policy information from cynara
-
/*Uninstall all user apps*/
std::vector<std::string> userApps;
try {
}
}
+ CynaraAdmin::getInstance().UserRemove(uidDeleted);
+
+ return ret;
+}
+
+int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+ enum {
+ NOT_CHECKED,
+ IS_NOT_ADMIN,
+ IS_ADMIN
+ } isAdmin = NOT_CHECKED;
+
+ try {
+ std::string uidStr = std::to_string(uid);
+ std::string pidStr = std::to_string(pid);
+
+ if (policyEntries.size() == 0) {
+ LogError("Validation failed: policy update request is empty");
+ return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
+ };
+
+ if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+ LogError("Not enough permission to call: " << __FUNCTION__);
+ return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+ };
+
+ std::vector<CynaraAdminPolicy> validatedPolicies;
+
+ for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
+ bool forAdmin = false;
+ CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
+ int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
+
+ if (forAdmin && (isAdmin == NOT_CHECKED)) {
+ isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
+ };
+
+ if (ret == SECURITY_MANAGER_API_SUCCESS) {
+ if (!forAdmin
+ || (forAdmin && (isAdmin == IS_ADMIN))) {
+ validatedPolicies.push_back(std::move(cyap));
+ } else {
+ LogError("Not enough privilege to enforce admin policy");
+ return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+ };
+
+ } else
+ return ret;
+ };
+
+ // Apply updates
+ CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
+
+ } catch (const CynaraException::Base &e) {
+ LogError("Error while updating Cynara rules: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ } catch (const std::bad_alloc &e) {
+ LogError("Memory allocation error while updating Cynara rules: " << e.what());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ }
+
+ return SECURITY_MANAGER_API_SUCCESS;
+}
+
+int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
+ const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
+{
+ try {
+ std::string uidStr = std::to_string(uid);
+ std::string pidStr = std::to_string(pid);
+
+ if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+ LogError("Not enough permission to call: " << __FUNCTION__);
+ return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+ };
+
+ LogDebug("Filter is: C: " << filter.appId
+ << ", U: " << filter.user
+ << ", P: " << filter.privilege
+ << ", current: " << filter.currentLevel
+ << ", max: " << filter.maxLevel
+ );
+
+ std::vector<CynaraAdminPolicy> listOfPolicies;
+
+ //convert appId to smack label
+ std::string appLabel;
+ if (!filter.appId.compare(SECURITY_MANAGER_ANY))
+ appLabel = CYNARA_ADMIN_ANY;
+ else
+ generateAppLabel(filter.appId, appLabel);
+
+ std::string user = (!filter.user.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.user;
+ std::string privilege = (!filter.privilege.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.privilege;
+
+ LogDebug("App: " << filter.appId << ", Label: " << appLabel);
+
+ if (forAdmin) {
+ if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+ LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
+ return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+ };
+
+ //Fetch privileges from ADMIN bucket
+ CynaraAdmin::getInstance().ListPolicies(
+ CynaraAdmin::Buckets.at(Bucket::ADMIN),
+ appLabel,
+ user,
+ privilege,
+ listOfPolicies
+ );
+ LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
+ } else {
+ if (uidStr.compare(user)) {
+ if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+ LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
+ user = uidStr;
+ };
+ };
+ //Fetch privileges from PRIVACY_MANAGER bucket
+ CynaraAdmin::getInstance().ListPolicies(
+ CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
+ appLabel,
+ user,
+ privilege,
+ listOfPolicies
+ );
+ LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
+ };
+
+ for (const auto &policy : listOfPolicies) {
+ //ignore "jump to bucket" entries
+ if (policy.result == CYNARA_ADMIN_BUCKET)
+ continue;
+
+ policy_entry pe;
+
+ pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
+ pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
+ pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
+ pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
+
+ if (!forAdmin) {
+ // All policy entries in PRIVACY_MANAGER should be fully-qualified
+ pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+ CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
+ policy.client, policy.user, policy.privilege));
+ } else {
+ // Cannot reliably calculate maxLavel for policies from ADMIN bucket
+ pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
+ }
+
+
+ LogDebug(
+ "[policy_entry] app: " << pe.appId
+ << " user: " << pe.user
+ << " privilege: " << pe.privilege
+ << " current: " << pe.currentLevel
+ << " max: " << pe.maxLevel
+ );
+
+ policyEntries.push_back(pe);
+ };
+
+ } catch (const CynaraException::Base &e) {
+ LogError("Error while listing Cynara rules: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ } catch (const std::bad_alloc &e) {
+ LogError("Memory allocation error while listing Cynara rules: " << e.what());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ }
+
+
+ return SECURITY_MANAGER_API_SUCCESS;
+}
+
+int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
+{
+ try {
+ std::string uidStr = std::to_string(uid);
+ std::string pidStr = std::to_string(pid);
+
+ if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
+ LogWarning("Not enough permission to call: " << __FUNCTION__);
+ return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
+ };
+
+ LogDebug("Filter is: C: " << filter.appId
+ << ", U: " << filter.user
+ << ", P: " << filter.privilege
+ << ", current: " << filter.currentLevel
+ << ", max: " << filter.maxLevel
+ );
+
+ std::vector<uid_t> listOfUsers;
+
+ if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
+ LogDebug("User is privileged");
+ if (filter.user.compare(SECURITY_MANAGER_ANY)) {
+ LogDebug("Limitting Cynara query to user: " << filter.user);
+ try {
+ listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
+ } catch (std::invalid_argument &e) {
+ LogError("Invalid UID: " << e.what());
+ };
+ } else
+ CynaraAdmin::getInstance().ListUsers(listOfUsers);
+ } else {
+ LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
+ LogDebug("Fetching personal policy for user: " << uid);
+ listOfUsers.push_back(uid);
+ };
+ LogDebug("Fetching policy for " << listOfUsers.size() << " users");
+
+ for (const uid_t &uid : listOfUsers) {
+ LogDebug("User: " << uid);
+ std::string userStr = std::to_string(uid);
+ std::vector<std::string> listOfApps;
+
+ if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
+ LogDebug("Limitting Cynara query to app: " << filter.appId);
+ listOfApps.push_back(filter.appId);
+ } else {
+ PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
+ LogDebug("Found apps: " << listOfApps.size());
+ };
+
+ for (const std::string &appId : listOfApps) {
+ LogDebug("App: " << appId);
+ std::string smackLabelForApp;
+ std::vector<std::string> listOfPrivileges;
+
+ generateAppLabel(appId, smackLabelForApp);
+ // FIXME: also fetch privileges of global applications
+ PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
+
+ if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
+ LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
+ // FIXME: this filtering should be already performed by method fetching the privileges
+ if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
+ filter.privilege) == listOfPrivileges.end()) {
+ LogDebug("Application " << appId <<
+ " doesn't have the filteres privilege " << filter.privilege);
+ continue;
+ }
+ listOfPrivileges.clear();
+ listOfPrivileges.push_back(filter.privilege);
+ }
+
+ LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
+
+ for (const std::string &privilege : listOfPrivileges) {
+ LogDebug("Privilege: " << privilege);
+ policy_entry pe;
+
+ pe.appId = appId;
+ pe.user = userStr;
+ pe.privilege = privilege;
+
+ pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+ CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
+ smackLabelForApp, userStr, privilege));
+
+ pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
+ CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
+ smackLabelForApp, userStr, privilege));
+
+ LogDebug(
+ "[policy_entry] app: " << pe.appId
+ << " user: " << pe.user
+ << " privilege: " << pe.privilege
+ << " current: " << pe.currentLevel
+ << " max: " << pe.maxLevel
+ );
+
+ policyEntries.push_back(pe);
+ };
+ };
+ };
+
+ } catch (const CynaraException::Base &e) {
+ LogError("Error while listing Cynara rules: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ } catch (const std::bad_alloc &e) {
+ LogError("Memory allocation error while listing Cynara rules: " << e.what());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ }
+
+ return SECURITY_MANAGER_API_SUCCESS;
+}
+
+int policyGetDesc(std::vector<std::string> &levels)
+{
+ int ret = SECURITY_MANAGER_API_SUCCESS;
+
+ try {
+ CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
+ } catch (const CynaraException::OutOfMemory &e) {
+ LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
+ } catch (const CynaraException::InvalidParam &e) {
+ LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
+ } catch (const CynaraException::ServiceNotAvailable &e) {
+ LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
+ } catch (const CynaraException::Base &e) {
+ LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
+ return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
+ }
+
return ret;
}