From: Krzysztof Sasiak Date: Tue, 23 Dec 2014 14:53:09 +0000 (+0100) Subject: Policy update: server side implementation X-Git-Tag: accepted/tizen/3.0.2015.q1/common/20150320.110433~19 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F64%2F32764%2F31;hp=b17d250a247a11dc6b63657c4174f697f1f95e4d;p=platform%2Fcore%2Fsecurity%2Fsecurity-manager.git Policy update: server side implementation Change-Id: I920cc940b541c21607dd836d1f426c1f622ffbb2 Signed-off-by: Krzysztof Sasiak Signed-off-by: Rafal Krypa --- diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 156ff26..6620708 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -175,6 +175,26 @@ CynaraAdminPolicy::CynaraAdminPolicy(CynaraAdminPolicy &&that) that.result_extra = nullptr; } +CynaraAdminPolicy& CynaraAdminPolicy::operator=(CynaraAdminPolicy &&that) +{ + if (this != &that) { + bucket = that.bucket; + client = that.client; + user = that.user; + privilege = that.privilege; + result_extra = that.result_extra; + result = that.result; + + that.bucket = nullptr; + that.client = nullptr; + that.user = nullptr; + that.privilege = nullptr; + that.result_extra = nullptr; + }; + + return *this; +} + CynaraAdminPolicy::~CynaraAdminPolicy() { free(this->bucket); diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index 1f37f96..5ac9e42 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -80,6 +80,7 @@ struct CynaraAdminPolicy : cynara_admin_policy /* Move constructor is the way to go. */ CynaraAdminPolicy(CynaraAdminPolicy &&that); + CynaraAdminPolicy& operator=(CynaraAdminPolicy &&that); ~CynaraAdminPolicy(); }; diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index d281bc8..e88951b 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -102,6 +102,18 @@ int userAdd(uid_t uidAdded, int userType, uid_t uid); */ int userDelete(uid_t uidDeleted, uid_t uid); +/** + * Update policy in Cynara - proper privilege: http://tizen.org/privilege/systemsettings.admin + * is needed for this to succeed + * + * @param[in] policyEntries vector of policy chunks with instructions + * @param[in] uid identifier of requesting user + * @param[in] pid PID of requesting process + * @param[in] smackLabel smack label of requesting app + * + * @return API return code, as defined in protocols.h + */ +int policyUpdate(const std::vector &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel); } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 824b1a9..d32cdb5 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -20,6 +20,7 @@ * @author Michal Witanowski * @author Jacek Bukarewicz * @author Rafal Krypa + * @author Krzysztof Sasiak * @brief Implementation of the service methods */ @@ -38,12 +39,100 @@ #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); @@ -422,5 +511,65 @@ int userDelete(uid_t uidDeleted, uid_t uid) return ret; } +int policyUpdate(const std::vector &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 validatedPolicies; + + for (auto &entry : const_cast&>(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; +} + } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index f7b8d21..3cc07c1 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -94,6 +94,17 @@ private: void processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); + + /** + * Process policy update request + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + * @param uid Identifier of the user who sent the request + * @param pid PID of the process which sent the request + * @param smackLabel smack label of requesting app + */ + void processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel); }; } // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 8a20ca4..14109c7 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -127,6 +127,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, case SecurityModuleCall::USER_DELETE: processUserDelete(buffer, send, uid); break; + case SecurityModuleCall::POLICY_UPDATE: + processPolicyUpdate(buffer, send, uid, pid, smackLabel); + break; default: LogError("Invalid call: " << call_type_int); Throw(ServiceException::InvalidAction); @@ -233,4 +236,15 @@ void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_ } +void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel) +{ + int ret; + std::vector policyEntries; + + Deserialization::Deserialize(buffer, policyEntries); + + ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel); + Serialization::Serialize(send, ret); +} + } // namespace SecurityManager