From: Krzysztof Sasiak Date: Wed, 11 Feb 2015 11:37:05 +0000 (+0100) Subject: List policies: server side implementation X-Git-Tag: accepted/tizen/3.0.2015.q1/common/20150320.110433~14 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fsecurity%2Fsecurity-manager.git;a=commitdiff_plain;h=ae45de1ad6f570504a04664ba503217aad50f9ee List policies: server side implementation Change-Id: Ic771c46851a46847c007a06ecd65107465957bf8 Signed-off-by: Krzysztof Sasiak Signed-off-by: Rafal Krypa --- diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 80e5b88..6d19977 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -488,7 +488,7 @@ int CynaraAdmin::convertToPolicyType(const std::string &policy, bool forceRefres return DescriptionToType.at(policy); } -void CynaraAdmin::Check(const std::string &label, const std::string &privilege, const std::string &user, +void CynaraAdmin::Check(const std::string &label, const std::string &user, const std::string &privilege, const std::string &bucket, int &result, std::string &resultExtra, const bool recursive) { char *resultExtraCstr = nullptr; @@ -507,6 +507,28 @@ void CynaraAdmin::Check(const std::string &label, const std::string &privilege, } } +int CynaraAdmin::GetPrivilegeManagerCurrLevel(const std::string &label, const std::string &user, + const std::string &privilege) +{ + int result; + std::string resultExtra; + + Check(label, user, privilege, Buckets.at(Bucket::PRIVACY_MANAGER), result, resultExtra, true); + + return result; +} + +int CynaraAdmin::GetPrivilegeManagerMaxLevel(const std::string &label, const std::string &user, + const std::string &privilege) +{ + int result; + std::string resultExtra; + + Check(label, user, privilege, Buckets.at(Bucket::MAIN), result, resultExtra, true); + + return result; +} + Cynara::Cynara() { checkCynaraError( diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index 659b2db..a75e414 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -223,13 +223,40 @@ public: * all buckets linked with bucket provided */ void Check(const std::string &label, - const std::string &privilege, const std::string &user, + const std::string &privilege, const std::string &bucket, int &result, std::string &resultExtra, const bool recursive); + /** + * Get current policy level for privilege-manager functionality + * Returns current policy value for given application, user and privilege + * identifiers. + * + * @param label application Smack label + * @param user user identifier (uid) + * @param privilege privilege identifier + * @return current policy value + */ + int GetPrivilegeManagerCurrLevel(const std::string &label, const std::string &user, + const std::string &privilege); + + /** + * Get maximum policy level for privilege-manager functionality + * Returns maximum possible policy value for given application, user and privilege + * identifiers. The maximum limit is imposed by other policy settings that are + * currently in place. + * + * @param label application Smack label + * @param user user identifier (uid) + * @param privilege privilege identifier + * @return maximum policy value for PRIVACY_MANAGER bucket + */ + int GetPrivilegeManagerMaxLevel(const std::string &label, const std::string &user, + const std::string &privilege); + private: CynaraAdmin(); diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index e88951b..c7c2711 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -113,7 +113,36 @@ int userDelete(uid_t uidDeleted, uid_t uid); * * @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); +/** + * Fetch all configured privileges from user configurable bucket. + * Depending on forAdmin value: personal user policies or admin enforced + * policies are returned. + * + * @param[in] forAdmin determines if user is asking as ADMIN or not + * @param[in] filter filter for limiting the query + * @param[in] uid identifier of queried user + * @param[in] pid PID of requesting process + * @param[out] policyEntries vector of policy entries with result + * + * @return API return code, as defined in protocols.h + */ +int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector &policyEntries); + +/** + * Fetch all privileges for all apps installed for specific user. + * + * @param[in] forAdmin determines if user is asking as ADMIN or not + * @param[in] filter filter for limiting the query + * @param[in] uid identifier of queried user + * @param[in] pid PID of requesting process + * @param[out] policyEntries vector of policy entries with result + * + * @return API return code, as defined in protocols.h + */ +int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector &policyEntries); + } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/common/include/smack-labels.h b/src/common/include/smack-labels.h index e45b085..3089462 100644 --- a/src/common/include/smack-labels.h +++ b/src/common/include/smack-labels.h @@ -47,6 +47,14 @@ bool setupPath(const std::string &pkgId, const std::string &path, app_install_path_type pathType); /** + * Generates application name for a label fetched from Cynara + * + * @param[in] label string to fetch application name for + * @return application name on success, empty string on error. +*/ +std::string generateAppNameFromLabel(const std::string &label); + +/** * Generates label for an application with a specific application ID * read from @ref appId and assigns it to @ref label. * diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index d32cdb5..6855337 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -571,5 +571,232 @@ int policyUpdate(const std::vector &policyEntries, uid_t uid, pid_ 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 &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 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 &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 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(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 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 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; +} + } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/common/smack-labels.cpp b/src/common/smack-labels.cpp index 7b68a45..616dd43 100644 --- a/src/common/smack-labels.cpp +++ b/src/common/smack-labels.cpp @@ -187,6 +187,12 @@ bool setupPath(const std::string &pkgId, const std::string &path, return labelDir(path, label, label_transmute, label_executables); } +std::string generateAppNameFromLabel(const std::string &label) +{ + //TODO: Fix when a label generating mechanism is ready + return label; +} + bool generateAppLabel(const std::string &appId, std::string &label) { (void) appId; diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 3cc07c1..9d0a420 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -94,7 +94,6 @@ private: void processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); - /** * Process policy update request * @@ -105,6 +104,34 @@ private: * @param smackLabel smack label of requesting app */ void processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel); + + /** + * List all privileges for specific user, placed in Cynara's PRIVACY_MANAGER + * or ADMIN's bucket - choice based on forAdmin parameter + * + * @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 + * @param forAdmin determines internal type of request + */ + void processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel, bool forAdmin); + + /** + * Get whole policy for specific user. Whole policy is a list of all apps, + * and their permissions (based on what they've stated in their manifests). + * If uid is unprivileged, then only privileges for the caller uid will be + * listed. If uid is privileged, then apps for all the users will be listed. + * + * @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 processGetPolicy(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 14109c7..a710871 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -130,6 +130,15 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, case SecurityModuleCall::POLICY_UPDATE: processPolicyUpdate(buffer, send, uid, pid, smackLabel); break; + case SecurityModuleCall::GET_CONF_POLICY_ADMIN: + processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, true); + break; + case SecurityModuleCall::GET_CONF_POLICY_SELF: + processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, false); + break; + case SecurityModuleCall::GET_POLICY: + processGetPolicy(buffer, send, uid, pid, smackLabel); + break; default: LogError("Invalid call: " << call_type_int); Throw(ServiceException::InvalidAction); @@ -235,7 +244,6 @@ void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_ Serialization::Serialize(send, ret); } - void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel) { int ret; @@ -247,4 +255,32 @@ void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, ui Serialization::Serialize(send, ret); } +void Service::processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel, bool forAdmin) +{ + int ret; + policy_entry filter; + Deserialization::Deserialize(buffer, filter); + std::vector policyEntries; + ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries); + Serialization::Serialize(send, ret); + Serialization::Serialize(send, static_cast(policyEntries.size())); + for (const auto &policyEntry : policyEntries) { + Serialization::Serialize(send, policyEntry); + }; +} + +void Service::processGetPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel) +{ + int ret; + policy_entry filter; + Deserialization::Deserialize(buffer, filter); + std::vector policyEntries; + ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries); + Serialization::Serialize(send, ret); + Serialization::Serialize(send, static_cast(policyEntries.size())); + for (const auto &policyEntry : policyEntries) { + Serialization::Serialize(send, policyEntry); + }; +} + } // namespace SecurityManager