From 35702040818594d6cb14b09d6f8a05a1b6e316b2 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Tue, 27 Jan 2015 11:58:01 +0100 Subject: [PATCH 01/16] Require socket to be passed by systemd, don't create it on our own Socket configuration, including path, ownership, DAC and Smack configuration is handled by systemd socket file. There is no point in duplicating that in the code as the service will always be run by systemd anyway. Existing socket configuration was also wrong and different from what systemd had. Change-Id: I4131ecf4cd0d886aec57a932c6540f10da9785a3 Signed-off-by: Rafal Krypa --- src/server/main/include/generic-socket-manager.h | 5 ++++- src/server/main/socket-manager.cpp | 8 +++++++- src/server/service/service.cpp | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/server/main/include/generic-socket-manager.h b/src/server/main/include/generic-socket-manager.h index 5234871..ef7c0c6 100644 --- a/src/server/main/include/generic-socket-manager.h +++ b/src/server/main/include/generic-socket-manager.h @@ -59,17 +59,20 @@ struct GenericSocketService { ServiceDescription(const char *path, const char *smackLabel, InterfaceID interfaceID = 0, - bool useSendMsg = false) + bool useSendMsg = false, + bool systemdOnly = false) : smackLabel(smackLabel) , interfaceID(interfaceID) , serviceHandlerPath(path) , useSendMsg(useSendMsg) + , systemdOnly(systemdOnly) {} SmackLabel smackLabel; // Smack label for socket InterfaceID interfaceID; // All data from serviceHandlerPath will be marked with this interfaceHandler ServiceHandlerPath serviceHandlerPath; // Path to file bool useSendMsg; + bool systemdOnly; }; typedef std::vector ServiceDescriptionVector; diff --git a/src/server/main/socket-manager.cpp b/src/server/main/socket-manager.cpp index 7341c7f..d917a68 100644 --- a/src/server/main/socket-manager.cpp +++ b/src/server/main/socket-manager.cpp @@ -545,8 +545,14 @@ void SocketManager::CreateDomainSocket( const GenericSocketService::ServiceDescription &desc) { int sockfd = GetSocketFromSystemD(desc); - if (-1 == sockfd) + if (-1 == sockfd) { + if (desc.systemdOnly) { + LogError("Socket " << desc.serviceHandlerPath << " not provided by systemd."); + ThrowMsg(Exception::InitFailed, "Socket " << desc.serviceHandlerPath << + " must be provided by systemd, but it was not."); + } sockfd = CreateDomainSocketHelp(desc); + } auto &description = CreateDefaultReadSocketDescription(sockfd, false); diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index faa337c..7f75bed 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -43,7 +43,11 @@ Service::Service() GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription() { return ServiceDescriptionVector { - {SERVICE_SOCKET, "security-manager", IFACE}, + {SERVICE_SOCKET, /* path */ + "*", /* smackLabel label (not used, we rely on systemd) */ + IFACE, /* InterfaceID */ + false, /* useSendMsg */ + true}, /* systemdOnly */ }; } -- 2.7.4 From f4630ca69bc060f363c91ab9dab488664b6e759f Mon Sep 17 00:00:00 2001 From: Sebastian Grabowski Date: Tue, 13 Jan 2015 13:16:23 +0100 Subject: [PATCH 02/16] Doc: correct misleading description of functions in service_impl.h Change-Id: I3a870ca7bb9d8c52dc49a202290950ef4a4356ba Signed-off-by: Sebastian Grabowski --- src/common/include/service_impl.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index 3df8975..d281bc8 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -40,7 +40,7 @@ namespace ServiceImpl { * @param[in] req installation request * @param[in] uid id of the requesting user * - * @return API return code, as defined in security-manager.h + * @return API return code, as defined in protocols.h */ int appInstall(const app_inst_req &req, uid_t uid); @@ -50,7 +50,7 @@ int appInstall(const app_inst_req &req, uid_t uid); * @param[in] req uninstallation request * @param[in] uid id of the requesting user * - * @return API return code, as defined in security-manager.h + * @return API return code, as defined in protocols.h */ int appUninstall(const std::string &appId, uid_t uid); @@ -61,7 +61,7 @@ int appUninstall(const std::string &appId, uid_t uid); * @param[in] appId application identifier * @param[out] pkgId returned package identifier * - * @return API return code, as defined in security-manager.h + * @return API return code, as defined in protocols.h */ int getPkgId(const std::string &appId, std::string &pkgId); @@ -77,7 +77,7 @@ int getPkgId(const std::string &appId, std::string &pkgId); * @param[in] pid id of the requesting process (to construct Cynara session id) * @param[out] gids returned set of allowed group ids * - * @return API return code, as defined in security-manager.h + * @return API return code, as defined in protocols.h */ int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids); -- 2.7.4 From 903a155d4bb4946726aff94103c204e2f72aee2d Mon Sep 17 00:00:00 2001 From: Marcin Lis Date: Fri, 19 Dec 2014 22:51:44 +0100 Subject: [PATCH 03/16] Change "operation" argument type in CynaraAdminPolicy constructor This change is needed in for policy updates. We need to support wide spectrum of results, starting from DENY (0) to ALLOW (0xFFFF). SM should not be limited to few enum class literals. Change-Id: I1e8d26893120309f6d6276da4bb5e146936a7e59 Signed-off-by: Marcin Lis --- src/common/cynara.cpp | 12 ++++++------ src/common/include/cynara.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 030041f..39b7e05 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -113,7 +113,7 @@ CynaraAdmin::BucketsMap CynaraAdmin::Buckets = CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user, - const std::string &privilege, Operation operation, + const std::string &privilege, int operation, const std::string &bucket) { this->client = strdup(client.c_str()); @@ -131,7 +131,7 @@ CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::strin std::string("Error in CynaraAdminPolicy allocation.")); } - this->result = static_cast(operation); + this->result = operation; this->result_extra = nullptr; } @@ -271,14 +271,14 @@ void CynaraAdmin::UpdateAppPolicy( LogDebug("(user = " << user << " label = " << label << ") " << "removing privilege " << *oldIter); policies.push_back(CynaraAdminPolicy(label, user, *oldIter, - CynaraAdminPolicy::Operation::Delete, + static_cast(CynaraAdminPolicy::Operation::Delete), Buckets.at(Bucket::MANIFESTS))); ++oldIter; } else { LogDebug("(user = " << user << " label = " << label << ") " << "adding privilege " << *newIter); policies.push_back(CynaraAdminPolicy(label, user, *newIter, - CynaraAdminPolicy::Operation::Allow, + static_cast(CynaraAdminPolicy::Operation::Allow), Buckets.at(Bucket::MANIFESTS))); ++newIter; } @@ -288,7 +288,7 @@ void CynaraAdmin::UpdateAppPolicy( LogDebug("(user = " << user << " label = " << label << ") " << "removing privilege " << *oldIter); policies.push_back(CynaraAdminPolicy(label, user, *oldIter, - CynaraAdminPolicy::Operation::Delete, + static_cast(CynaraAdminPolicy::Operation::Delete), Buckets.at(Bucket::MANIFESTS))); } @@ -296,7 +296,7 @@ void CynaraAdmin::UpdateAppPolicy( LogDebug("(user = " << user << " label = " << label << ") " << "adding privilege " << *newIter); policies.push_back(CynaraAdminPolicy(label, user, *newIter, - CynaraAdminPolicy::Operation::Allow, + static_cast(CynaraAdminPolicy::Operation::Allow), Buckets.at(Bucket::MANIFESTS))); } diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index 97a6375..ce103f0 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -68,7 +68,7 @@ struct CynaraAdminPolicy : cynara_admin_policy }; CynaraAdminPolicy(const std::string &client, const std::string &user, - const std::string &privilege, Operation operation, + const std::string &privilege, int operation, const std::string &bucket = std::string(CYNARA_ADMIN_DEFAULT_BUCKET)); CynaraAdminPolicy(const std::string &client, const std::string &user, -- 2.7.4 From 0fc7b95468c6c61389e406c0ae4cc73973768b4c Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Tue, 27 Jan 2015 12:06:44 +0100 Subject: [PATCH 04/16] Terminate service if it cannot setup its sockets Currently even if the server cannot listen on a socket it will continue running. There is no point in that, when no client will be able to connect. Change-Id: I74ad5a9fddee1072f7642c036a088805f53caa11 Signed-off-by: Rafal Krypa --- src/server/main/server-main.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/server/main/server-main.cpp b/src/server/main/server-main.cpp index 5c34d3f..c9609e2 100644 --- a/src/server/main/server-main.cpp +++ b/src/server/main/server-main.cpp @@ -39,14 +39,14 @@ IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem); registerSocketService(manager, #service) template -void registerSocketService(SecurityManager::SocketManager &manager, const std::string& serviceName) +bool registerSocketService(SecurityManager::SocketManager &manager, const std::string& serviceName) { T *service = NULL; try { service = new T(); service->Create(); manager.RegisterSocketService(service); - service = NULL; + return true; } catch (const SecurityManager::Exception &exception) { LogError("Error in creating service " << serviceName << ", details:\n" << exception.DumpToString()); @@ -59,6 +59,7 @@ void registerSocketService(SecurityManager::SocketManager &manager, const std::s } if (service) delete service; + return false; } int main(void) { @@ -82,7 +83,10 @@ int main(void) { LogInfo("Start!"); SecurityManager::SocketManager manager; - REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service); + if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service)) { + LogError("Unable to create socket service. Exiting."); + return EXIT_FAILURE; + } manager.MainLoop(); } catch (const SecurityManager::FileLocker::Exception::Base &e) { -- 2.7.4 From e23799e92c97db9c8528c32218a9d9457e44064c Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Sat, 31 Jan 2015 10:38:33 +0100 Subject: [PATCH 05/16] Add API stub for setting policies Change-Id: I56ccafe0432c44e7f5f97abd9f1aa29ff76e4c47 Signed-off-by: Jan Cybulski --- src/client/client-security-manager.cpp | 109 ++++++++++++++ src/common/include/protocols.h | 15 ++ src/include/security-manager.h | 262 +++++++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index c3f72d9..c2a3fd7 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -634,3 +634,112 @@ int security_manager_user_delete(const user_req *p_req) } }); } + + +/***************************POLICY***************************************/ + +SECURITY_MANAGER_API +int security_manager_policy_update_req_new(policy_update_req **pp_req) +{ + if (!pp_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + + try { + *pp_req = new policy_update_req; + } catch (std::bad_alloc& ex) { + return SECURITY_MANAGER_ERROR_MEMORY; + } + + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +void security_manager_policy_update_req_free(policy_update_req *p_req) +{ + delete p_req; +} + +SECURITY_MANAGER_API +int security_manager_policy_update_send(policy_update_req *p_req) +{ + (void)p_req; + + return SECURITY_MANAGER_ERROR_UNKNOWN; +} + + +SECURITY_MANAGER_API +int security_manager_policy_entry_new(policy_entry **p_entry) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + + try { + *p_entry = new policy_entry; + } catch (std::bad_alloc& ex) { + return SECURITY_MANAGER_ERROR_MEMORY; + } + + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +void security_manager_policy_entry_free(policy_entry *p_entry) +{ + delete p_entry; +} + +SECURITY_MANAGER_API +int security_manager_policy_entry_set_application(policy_entry *p_entry, const char *app_id) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_entry->appId = app_id; + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_policy_entry_set_user(policy_entry *p_entry, const char *user) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_entry->user = user; + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_policy_entry_set_privilege(policy_entry *p_entry, const char *privilege) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_entry->privilege = privilege; + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_policy_entry_set_level(policy_entry *p_entry, const char *policy_level) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_entry->currentLevel = policy_level; + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_policy_entry_admin_set_level(policy_entry *p_entry, const char *policy_level) +{ + if (!p_entry) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_entry->maxLevel = policy_level; + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_policy_update_req_add_entry(policy_update_req *p_req, const policy_entry *p_entry) +{ + if (!p_entry || !p_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + p_req->units.push_back(p_entry); + + return SECURITY_MANAGER_SUCCESS; +} diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 11b93a5..1d52dd4 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -130,4 +130,19 @@ enum class SecurityModuleCall } // namespace SecurityManager +struct policy_entry { + std::string user; // uid converted to string + std::string appId; // application identifier + std::string privilege; // cynara privilege + std::string currentLevel; // current level of privielege, or level asked to be set in privacy manager bucket + std::string maxLevel; // holds read maximum policy status or status to be set in admin bucket +}; +typedef struct policy_entry policy_entry; + + +struct policy_update_req { + std::vector units; +}; + + #endif // _SECURITY_MANAGER_PROTOCOLS_ diff --git a/src/include/security-manager.h b/src/include/security-manager.h index 5e0f15b..0dd5378 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -81,6 +81,21 @@ typedef struct app_inst_req app_inst_req; struct user_req; typedef struct user_req user_req; +/*! \brief data structure responsible for handling policy updates + * required to manage users' and applications' permissions */ +struct policy_update_req; +typedef struct policy_update_req policy_update_req; + +/*! \brief data structure responsible for handling single policy entry*/ +struct policy_entry; +typedef struct policy_entry policy_entry; + +/*! \brief wildcard to be used in policy update requests to match all possible values of + * given field. Use it, for example when it is desired to apply policy change for all + * users or all apps for selected user. + */ +#define SECURITY_MANAGER_ANY "#" + /** * This function translates lib_retcode error codes to strings describing * errors. @@ -305,6 +320,253 @@ int security_manager_user_add(const user_req *p_req); */ int security_manager_user_delete(const user_req *p_req); +/** + * \brief This function is responsible for initializing policy_update_req data structure. + * + * It uses dynamic allocation inside and user responsibility is to call + * policy_update_req_free() for freeing allocated resources. + * + * \param[out] pp_req Address of pointer for handle policy_update_req structure + * \return API return code or error code + */ +int security_manager_policy_update_req_new(policy_update_req **pp_req); + +/** + * \brief This function is used to free resources allocated by calling policy_update_req_new(). + * \param[in] p_req Pointer handling allocated policy_update_req structure + */ +void security_manager_policy_update_req_free(policy_update_req *p_req); + +/** + * \brief This function is responsible for initializing policy_entry data structure. + * + * It uses dynamic allocation inside and user responsibility is to call + * policy_policy_entry_free() for freeing allocated resources. + * + * \param[out] pp_entry Address of pointer for handle policy_entry structure + * \return API return code or error code + */ +int security_manager_policy_entry_new(policy_entry **pp_entry); + +/** + * \brief This function is used to free resources allocated by calling + * policy_entry_req_new(). + * \param[in] p_entry Pointer handling allocated policy_entry structure + */ +void security_manager_policy_entry_free(policy_entry *p_entry); + +/** + * This function is used to set up application identifier in p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \param[in] app_id Application identifier to be set + * \return API return code or error code + */ +int security_manager_policy_entry_set_application(policy_entry *p_entry, const char *app_id); + +/** + * This function is used to set up user identifier in p_entry structure + * Calling this function may be omitted if user wants to set policies for himself + * \param[in] p_entry Pointer handling policy_entry structure + * \param[in] user_id User identifier to be set + * \return API return code or error code + */ +int security_manager_policy_entry_set_user(policy_entry *p_entry, const char *user_id); + +/** + * This function is used to set up privilege in p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \param[in] privilege Privilege to be set + * \return API return code or error code + */ +int security_manager_policy_entry_set_privilege(policy_entry *p_entry, const char *privilege); + +/** + * This function is used to set up privilege level in p_entry structure. + * This api is intended to be used to decrease user's own level of privilege. + * + * \param[in] p_entry Pointer handling policy_entry structure + * \param[in] policy_level Policy level to be set. The level of privilege may + * be one of strings returned by @ref security_manager_policy_levels_get. + * If it is not, then error code SECURITY_MANAGER_ERROR_INPUT_PARAM is returned. + * Two predefined values are always valid here: + * + * "Allow", which means that user allows some app (setup by calling function + * @ref security_manager_policy_entry_set_application) to run with some privilege + * (setup by @ref security_manager_policy_entry_set_privilege). + * Note, that this not necessarily mean, that this privilege will really be granted. + * Final decision of granting privilege also depends on app's manifests, + * predefined policy and administrator's or manufacturer's settings. + * If all of those policy sources also allows granting privilege for that app, + * then (and only then) it will be granted. + * + * "Deny", which means that user disallows some app (setup by calling function + * @ref security_manager_policy_entry_set_application) to run with some privilege + * (setup by @ref security_manager_policy_entry_set_privilege). + * Note, that this denies privilege irrespective of privilege levels granted + * to app by other policy sources: app's manifests, predefined policy + * and administrator's or manufacturer's settings. + * + * Other levels may be also valid, if returned by security_manager_policy_levels_get. + * They represent other policy levels configured in system, which security-manager + * does support. The other levels are always something between "Allow" and "Deny" + * (like "Allow only once"). + * + * Irrespective of a meaning of those values security-manager will always treat + * policy set by security_manager_policy_entry_set_level as a mean to + * decrease user's own rights. This will never increase overall policy. + * + * \return API return code or error code + */ +int security_manager_policy_entry_set_level(policy_entry *p_entry, const char *policy_level); + +/** + * This function is used to set up privilege level for admin policy entries + * in p_entry structure. + * + * This function is intended to be used by admin to change level of privilege. + * If it is used by user that has no http://tizen.org/privilege/systemsettings.admin + * privilege, then security_manager_policy_update_send will return error code. + * + * \param[in] p_entry Pointer handling policy_entry structure + * \param[in] policy_level Policy level to be set. This may be one of strings + * returned by @ref security_manager_policy_levels_get. If it is not, then error + * code is returned (SECURITY_MANAGER_ERROR_INPUT_PARAM). + * Two predefined values are always valid here: + * + * "Allow", which means that admin allows some user's app to + * get privilege irrespective of predefined policy settings for that user. + * Note, that this not necessarily mean, that this privilege will really be granted. + * Final decision of granting privilege also depends on app's manifests, + * user's own policy (set up by @ref security_manager_policy_entry_set_level) + * or manufacturer's settings. + * If all of those policy sources also allows granting privilege for that app, + * then (and only then) it will be granted. + * + * "Deny", which means that admin disallows some user's app to get privilege + * irrespective of predefined policy settings for that user. + * Note, that this denies privilege app's manifests, user's own policy + * (set up by @ref security_manager_policy_entry_set_level) or manufacturer's + * settings. + * + * Other levels may be also valid, if returned by security_manager_policy_levels_get. + * They represent other policy levels configured in system, which security-manager + * does support. The other levels are always something between "Allow" and "Deny" + * (like "Allow only once"). + * + * Irrespective of a meaning of those values security-manager will always treat + * policy set by security_manager_policy_entry_admin_set_level as a mean for admin + * to change user's rights, but will not alter user's own privilege level set up + * by @ref security_manager_policy_entry_set_level. + * + * \return API return code or error code + */ +int security_manager_policy_entry_admin_set_level(policy_entry *p_entry, const char *policy_level); + +/** + * This function is used to add policy entry to policy update request. + * + * Note, that this function does not make a copy of object pointed to by p_entry + * and does not change owner of this handler. + * User is responsible to keep p_entry untouched until @ref security_manager_policy_update_send + * is called on p_req. After that p_entry still needs to be freed. + * (see examples in documentation of @ref security_manager_policy_update_send) + * + * \param[in] p_req Pointer handling allocated policy_update_req structure + * \param[in] p_entry Pointer handling policy_entry structure + * \return API return code or error code + */ +int security_manager_policy_update_req_add_entry(policy_update_req *p_req, const policy_entry *p_entry); + +/** + * \brief This function is used to send the prepared policy update request to scurity-manager daemon. + * + * \param[in] p_req Pointer handling allocated policy_update_req structure + * \return API return code or error code + * + * Example: + * (warning: checking return codes are omitted in examples just for visibility reasons) + * + * - to update policy for user by himself: + * (Deny access from app MyApp1 to privilege http://tizen.org/privilege/systemsettings, + * deny access from app MyApp2 to privilege http://tizen.org/privilege/systemsettings, + * deny access from app MyApp3 to privilege http://tizen.org/privilege/notificationmanager) + * + * policy_update_req *policy_update_request; + * policy_entry *entry1; + * policy_entry *entry2; + * policy_entry *entry3; + * + * security_manager_policy_update_req_new(&policy_update_request); + * security_manager_policy_entry_new(&entry1); + * security_manager_policy_entry_new(&entry2); + * security_manager_policy_entry_new(&entry3); + * + * security_manager_policy_entry_set_application(entry1, "MyApp1"); + * security_manager_policy_entry_set_privilege(entry1, "http://tizen.org/privilege/systemsettings"); + * security_manager_policy_entry_set_level(entry1, "Deny"); + * + * security_manager_policy_entry_set_application(entry2, "MyApp2"); + * security_manager_policy_entry_set_privilege(entry2, "http://tizen.org/privilege/systemsettings"); + * security_manager_policy_entry_set_level(entry2, "Deny"); + * + * security_manager_policy_entry_set_application(entry3, "MyApp3"); + * security_manager_policy_entry_set_privilege(entry3, "http://tizen.org/privilege/notificationmanager"); + * security_manager_policy_entry_set_level(entry3, "Deny"); + * + * security_manager_policy_update_req_add_entry(policy_update_request, entry1); + * security_manager_policy_update_req_add_entry(policy_update_request, entry2); + * security_manager_policy_update_req_add_entry(policy_update_request, entry3); + * + * //do not change entry1, entry2 or entry3! + * + * security_manager_policy_update_send(policy_update_request); + * + * security_manager_policy_entry_free(entry1); + * security_manager_policy_entry_free(entry2); + * security_manager_policy_entry_free(entry3); + * security_manager_policy_update_free(policy_update_request); + * + * - to update policy by administrator for some user: + * (Deny access of user of uid 2001 from any app to privilege http://tizen.org/privilege/vibrator, + * (allow access of user of uid 2002 using app "App1" to privilege http://tizen.org/privilege/email.admin) + * + * policy_update_req *policy_update_request; + * + * security_manager_policy_update_req_new(&policy_update_request); + + * policy_entry *entry1; + * policy_entry *entry2; + * char *adminswife = "2001"; + * char *adminsfriend = "2002"; + * + * security_manager_policy_entry_new(&entry1); + * security_manager_policy_entry_new(&entry2); + * + * security_manager_policy_entry_set_user(entry1, adminswife); + * security_manager_policy_entry_set_application(entry1, SECURITY_MANAGER_ANY); + * security_manager_policy_entry_set_privilege(entry1, "http://tizen.org/privilege/vibrator"); + * security_manager_policy_entry_admin_set_level(entry1, "Deny"); + * + * security_manager_policy_entry_set_user(entry2, adminsfriend); + * security_manager_policy_entry_set_application(entry2, "App1"); + * security_manager_policy_entry_set_privilege(entry2, "http://tizen.org/privilege/email.admin"); + * security_manager_policy_entry_admin_set_level(entry2, "Allow"); + * + * security_manager_policy_update_req_add_entry(policy_update_request, entry1); + * security_manager_policy_update_req_add_entry(policy_update_request, entry2); + * + * //do not change entry1 or entry2! + * + * security_manager_policy_update_send(policy_update_request); + * + * security_manager_policy_entry_free(entry1); + * security_manager_policy_entry_free(entry2); + * security_manager_policy_update_free(policy_update_request); + * + */ +int security_manager_policy_update_send(policy_update_req *p_req); #ifdef __cplusplus } -- 2.7.4 From 600f701fc427198821787336be9c5c2f92256a04 Mon Sep 17 00:00:00 2001 From: Krzysztof Sasiak Date: Sat, 31 Jan 2015 11:11:18 +0100 Subject: [PATCH 06/16] Add API stub for getting policy entries Change-Id: I4eaa9642b81d6524038ec18bcfe7ad55dc61b697 Signed-off-by: Jan Cybulski Signed-off-by: Krzysztof Sasiak --- src/client/client-security-manager.cpp | 87 ++++++++++++++++++++++++ src/include/security-manager.h | 119 ++++++++++++++++++++++++++++++++- 2 files changed, 205 insertions(+), 1 deletion(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index c2a3fd7..c7fe2a7 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -667,6 +667,41 @@ int security_manager_policy_update_send(policy_update_req *p_req) return SECURITY_MANAGER_ERROR_UNKNOWN; } +SECURITY_MANAGER_API +int security_manager_get_configured_policy_for_admin( + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size) +{ + (void)p_filter; + (void)pp_privs_policy; + (void)p_size; + return SECURITY_MANAGER_ERROR_UNKNOWN; +} + +SECURITY_MANAGER_API +int security_manager_get_configured_policy_for_self( + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size) +{ + (void)p_filter; + (void)pp_privs_policy; + (void)p_size; + return SECURITY_MANAGER_ERROR_UNKNOWN; +} + + +int security_manager_get_policy( + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size) +{ + (void)p_filter; + (void)pp_privs_policy; + (void)p_size; + return SECURITY_MANAGER_ERROR_UNKNOWN; +} SECURITY_MANAGER_API int security_manager_policy_entry_new(policy_entry **p_entry) @@ -743,3 +778,55 @@ int security_manager_policy_update_req_add_entry(policy_update_req *p_req, const return SECURITY_MANAGER_SUCCESS; } + +SECURITY_MANAGER_API +const char *security_manager_policy_entry_get_user(policy_entry *p_entry) +{ + if (p_entry) + return strdup(p_entry->user.c_str()); + else + return nullptr; +} + +SECURITY_MANAGER_API +const char *security_manager_policy_entry_get_application(policy_entry *p_entry) +{ + if (p_entry) + return strdup(p_entry->appId.c_str()); + else + return nullptr; +} +SECURITY_MANAGER_API +const char *security_manager_policy_entry_get_privilege(policy_entry *p_entry) +{ + if (p_entry) + return strdup(p_entry->privilege.c_str()); + else + return nullptr; +} +SECURITY_MANAGER_API +const char *security_manager_policy_entry_get_level(policy_entry *p_entry) +{ + if (p_entry) + return strdup(p_entry->currentLevel.c_str()); + else + return nullptr; +} + +SECURITY_MANAGER_API +const char *security_manager_policy_entry_get_max_level(policy_entry *p_entry) +{ + if (p_entry) + return strdup(p_entry->maxLevel.c_str()); + else + return nullptr; +} + +SECURITY_MANAGER_API +void security_manager_policy_entries_free(policy_entry *p_entries, const size_t size) +{ + for (size_t i = 0; i < size; i++) { + delete &p_entries[i]; + } + delete [] p_entries; +} diff --git a/src/include/security-manager.h b/src/include/security-manager.h index 0dd5378..9e8a536 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -480,7 +480,58 @@ int security_manager_policy_entry_admin_set_level(policy_entry *p_entry, const c int security_manager_policy_update_req_add_entry(policy_update_req *p_req, const policy_entry *p_entry); /** - * \brief This function is used to send the prepared policy update request to scurity-manager daemon. + * This function is used to obtain user ID from p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \attention Warning: memory pointed to by value written to policy_level needs to be freed + * + * \return user uid + */ + +const char *security_manager_policy_entry_get_user(policy_entry *p_entry); +/** + * This function is used to obtain application name from p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \attention Warning: memory pointed to by value written to policy_level needs to be freed + * + * \return application name + */ + +const char *security_manager_policy_entry_get_application(policy_entry *p_entry); +/** + * This function is used to obtain privilege name from p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \attention Warning: memory pointed to by value written to policy_level needs to be freed + * + * \return privilege name + */ +const char *security_manager_policy_entry_get_privilege(policy_entry *p_entry); +/** + * This function is used to obtain current policy level from p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure + * \attention Warning: memory pointed to by value written to policy_level needs to be freed + * + * \return Current policy level + */ +const char *security_manager_policy_entry_get_level(policy_entry *p_entry); + +/** + * This function is used to obtain maximal policy level from p_entry structure + * + * \param[in] p_entry Pointer handling policy_entry structure. + * \attention Warning: memory pointed to by value written to policy_level needs to be freed + * + * \return Maximal policy level + */ +const char *security_manager_policy_entry_get_max_level(policy_entry *p_entry); + +/** + * \brief This function is used to send the prepared policy update request using privacy manager + * entry point. The request should contain at least one policy update unit, otherwise + * the SECURITY_MANAGER_ERROR_INPUT_PARAM is returned. * * \param[in] p_req Pointer handling allocated policy_update_req structure * \return API return code or error code @@ -568,6 +619,72 @@ int security_manager_policy_update_req_add_entry(policy_update_req *p_req, const */ int security_manager_policy_update_send(policy_update_req *p_req); +/** + * \brief Function fetches all privileges enforced by admin user. + * The result is stored in the policy_entry structures array. + * + * \note It should be called by user with http://tizen.org/privilege/systemsettings.admin privilege. + * Normal users may list their personal policy entries using + * security_manager_get_configured_policy_for_self() API function. + * + * \attention Developer is responsible for calling security_manager_policy_entries_free() + * for freeing allocated resources. + * + * \param[in] p_filter Pointer to filter struct + * \param[out] pp_privs_policy Pointer handling allocated policy_entry structures array + * \param[out] p_size Pointer where the size of allocated array will be stored + * \return API return code or error code + */ +int security_manager_get_configured_policy_for_admin( + policy_entry *p_filter, + policy_entry **pp_privs_policy, size_t *p_size); + +/** + * \brief Function fetches all privileges that are configured by user in his/her + * privacy manager. The result is stored in the policy_entry structures array. + * User may only fetch privileges for his/her own UID. + * + * \attention Developer is responsible for calling security_manager_policy_entries_free() + * for freeing allocated resources. + * + * \param[in] p_filter Pointer to filter struct + * \param[out] pp_privs_policy Pointer handling allocated policy_entry structures array + * \param[out] p_size Pointer where the size of allocated array will be stored + * \return API return code or error code + */ +int security_manager_get_configured_policy_for_self( + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size); + +/** + * \brief Function gets the whole policy for all users, their applications and privileges + * based on the provided filter. The result is stored in the policy_entry array. + * + * \note If this call is performed by user with http://tizen.org/privilege/systemsettings.admin + * privilege, then it's possible to list policies for all users. + * Normal users may only list privileges for their own UID. + * + * \attention Developer is responsible for calling security_manager_policy_entries_free() + * for freeing allocated resources. + * + * \param[in] p_filter Pointer to filter struct + * \param[out] pp_privs_policy Pointer handling allocated policy_entry structures array + * \param[out] p_size Pointer where the size of allocated array will be stored + * \return API return code or error code + */ +int security_manager_get_policy( + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size); + +/** + * \brief This function is used to free resources allocated in policy_entry structures array. + * \param[in] p_entries Pointer handling allocated policy status array + * \param[in] size Size of the array + */ +void security_manager_policy_entries_free(policy_entry *p_entries, const size_t size); + #ifdef __cplusplus } #endif -- 2.7.4 From a98984da0831a6136a4dedfcac283b9484085d19 Mon Sep 17 00:00:00 2001 From: Michal Eljasiewicz Date: Mon, 2 Feb 2015 15:52:40 +0100 Subject: [PATCH 07/16] API stub for getting policy levels as strings Change-Id: I140d2d05763974d0400825220e422984bf1cde55 Signed-off-by: Michal Eljasiewicz --- src/client/client-security-manager.cpp | 16 ++++++++++++++++ src/include/security-manager.h | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index c7fe2a7..05b84f2 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -830,3 +830,19 @@ void security_manager_policy_entries_free(policy_entry *p_entries, const size_t } delete [] p_entries; } + +SECURITY_MANAGER_API +int security_manager_policy_levels_get(char ***levels, size_t *levels_count) +{ + (void)levels; + (void)levels_count; + + return 0; +} + +SECURITY_MANAGER_API +void security_manager_policy_levels_free(char **levels, size_t levels_count) +{ + (void)levels; + (void)levels_count; +} diff --git a/src/include/security-manager.h b/src/include/security-manager.h index 9e8a536..fa77321 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -685,6 +685,30 @@ int security_manager_get_policy( */ void security_manager_policy_entries_free(policy_entry *p_entries, const size_t size); +/** + * This function returns array of available policy levels in form of simple + * text descriptions. List is sorted using internal policy level value, + * from highest value to lowest and starts with "Allow". + * + * Caller needs to free memory allocated for the list using + * security_manager_policy_levels_free(). + * + * @param levels pointer to array of strings. + * @param levels_count number of strings in levels array. + * @return API return code or error code. + */ +int security_manager_policy_levels_get(char ***levels, size_t *levels_count); + +/** + * This function free memory allocated by security_manager_policy_levels_get() + * function. + * + * @param levels array of strings returned by + * security_manager_policy_levels_get() function. + * @return API return code or error code. + */ +void security_manager_policy_levels_free(char **levels, size_t levels_count); + #ifdef __cplusplus } #endif -- 2.7.4 From ed455f0c98a862fe06adf5da6c9ba8089bc0c116 Mon Sep 17 00:00:00 2001 From: Krzysztof Sasiak Date: Sat, 31 Jan 2015 12:25:19 +0100 Subject: [PATCH 08/16] Implementation of client stubs for updating and fetching policy Change-Id: I75089fb79488a1660f2270a7140ffc00778e7b7c --- src/client/client-security-manager.cpp | 104 ++++++++++++++++++++++++++++----- src/common/include/protocols.h | 31 +++++++++- 2 files changed, 117 insertions(+), 18 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 05b84f2..a11d4c4 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -662,9 +662,90 @@ void security_manager_policy_update_req_free(policy_update_req *p_req) SECURITY_MANAGER_API int security_manager_policy_update_send(policy_update_req *p_req) { - (void)p_req; + using namespace SecurityManager; + MessageBuffer send, recv; + + if (p_req == nullptr || p_req->units.size() == 0) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; - return SECURITY_MANAGER_ERROR_UNKNOWN; + return try_catch([&] { + + //put request into buffer + Serialization::Serialize(send, static_cast(SecurityModuleCall::POLICY_UPDATE)); + Serialization::Serialize(send, p_req->units); + + //send it to server + int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv); + if (retval != SECURITY_MANAGER_API_SUCCESS) { + LogError("Error in sendToServer. Error code: " << retval); + return SECURITY_MANAGER_ERROR_UNKNOWN; + } + + //receive response from server + Deserialization::Deserialize(recv, retval); + switch(retval) { + case SECURITY_MANAGER_API_SUCCESS: + return SECURITY_MANAGER_SUCCESS; + case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED: + return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED; + default: + return SECURITY_MANAGER_ERROR_UNKNOWN; + } + }); +} + +static inline int security_manager_get_policy_internal( + SecurityManager::SecurityModuleCall call_type, + policy_entry *p_filter, + policy_entry **pp_privs_policy, + size_t *p_size) +{ + using namespace SecurityManager; + MessageBuffer send, recv; + + if (pp_privs_policy == nullptr || p_size == nullptr) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + + return try_catch([&] { + //put request into buffer + Serialization::Serialize(send, static_cast(call_type)); + Serialization::Serialize(send, *p_filter); + //send it to server + int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv); + if (retval != SECURITY_MANAGER_API_SUCCESS) { + LogError("Error in sendToServer. Error code: " << retval); + return SECURITY_MANAGER_ERROR_UNKNOWN; + } + //receive response from server + Deserialization::Deserialize(recv, retval); + switch(retval) { + case SECURITY_MANAGER_API_SUCCESS: { + //extract and allocate buffers for privs policy entries + size_t entriesCnt = 0; + policy_entry **entries = nullptr; + Deserialization::Deserialize(recv, entriesCnt); + try { + entries = new policy_entry*[entriesCnt](); + for (size_t i = 0; i < entriesCnt; ++i) + Deserialization::Deserialize(recv, entries[i]); + } catch (...) { + LogError("Error while parsing server response"); + for (size_t i = 0; i < entriesCnt; ++i) + delete(entries[i]); + delete entries; + return SECURITY_MANAGER_ERROR_UNKNOWN; + } + *p_size = entriesCnt; + pp_privs_policy = entries; + return SECURITY_MANAGER_SUCCESS; + } + case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED: + return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED; + + default: + return SECURITY_MANAGER_ERROR_UNKNOWN; + } + }); } SECURITY_MANAGER_API @@ -673,10 +754,7 @@ int security_manager_get_configured_policy_for_admin( policy_entry **pp_privs_policy, size_t *p_size) { - (void)p_filter; - (void)pp_privs_policy; - (void)p_size; - return SECURITY_MANAGER_ERROR_UNKNOWN; + return security_manager_get_policy_internal(SecurityModuleCall::GET_CONF_POLICY_ADMIN, p_filter, pp_privs_policy, p_size); } SECURITY_MANAGER_API @@ -685,23 +763,17 @@ int security_manager_get_configured_policy_for_self( policy_entry **pp_privs_policy, size_t *p_size) { - (void)p_filter; - (void)pp_privs_policy; - (void)p_size; - return SECURITY_MANAGER_ERROR_UNKNOWN; + return security_manager_get_policy_internal(SecurityModuleCall::GET_CONF_POLICY_SELF, p_filter, pp_privs_policy, p_size); } - +SECURITY_MANAGER_API int security_manager_get_policy( policy_entry *p_filter, policy_entry **pp_privs_policy, size_t *p_size) { - (void)p_filter; - (void)pp_privs_policy; - (void)p_size; - return SECURITY_MANAGER_ERROR_UNKNOWN; -} + return security_manager_get_policy_internal(SecurityModuleCall::GET_POLICY, p_filter, pp_privs_policy, p_size); +}; SECURITY_MANAGER_API int security_manager_policy_entry_new(policy_entry **p_entry) diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 1d52dd4..907a41a 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -28,6 +28,7 @@ #include #include #include +#include /** * \name Return Codes @@ -126,16 +127,42 @@ enum class SecurityModuleCall APP_GET_GROUPS, USER_ADD, USER_DELETE, + POLICY_UPDATE, + GET_POLICY, + GET_CONF_POLICY_ADMIN, + GET_CONF_POLICY_SELF, }; } // namespace SecurityManager -struct policy_entry { +using namespace SecurityManager; + +struct policy_entry : ISerializable { std::string user; // uid converted to string std::string appId; // application identifier - std::string privilege; // cynara privilege + std::string privilege; // Cynara privilege std::string currentLevel; // current level of privielege, or level asked to be set in privacy manager bucket std::string maxLevel; // holds read maximum policy status or status to be set in admin bucket + + policy_entry() : user(""), appId(""), privilege(""), currentLevel(""), maxLevel("") + {} + + policy_entry(IStream &stream) { + Deserialization::Deserialize(stream, user); + Deserialization::Deserialize(stream, appId); + Deserialization::Deserialize(stream, privilege); + Deserialization::Deserialize(stream, currentLevel); + Deserialization::Deserialize(stream, maxLevel); + } + + virtual void Serialize(IStream &stream) const { + Serialization::Serialize(stream, user); + Serialization::Serialize(stream, appId); + Serialization::Serialize(stream, privilege); + Serialization::Serialize(stream, currentLevel); + Serialization::Serialize(stream, maxLevel); + } + }; typedef struct policy_entry policy_entry; -- 2.7.4 From 3a8e93b9741c6c0253ba1acbcdc6e5869cba6e5d Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Tue, 27 Jan 2015 12:09:14 +0100 Subject: [PATCH 09/16] Don't start the service on system boot, rely on socket activation Security-manager doesn't need to be started immediately on system boot. Systemd socket activation is already in place for lazy startup. Also previous configuration wrongly started security-manager.target, which caused the service to be launched without sockets passed from systemd. Change-Id: I7bff7b58a4e016119e651edfefb85a2335b8b31f Signed-off-by: Rafal Krypa --- packaging/security-manager.spec | 9 ++------- systemd/CMakeLists.txt | 1 - systemd/security-manager.service.in | 4 ---- systemd/security-manager.target | 4 ---- 4 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 systemd/security-manager.target diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index b39e24a..7da352b 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -84,9 +84,7 @@ mkdir -p %{buildroot}/%{TZ_SYS_SMACK} cp app-rules-template.smack %{buildroot}/%{TZ_SYS_SMACK} %make_install -mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants -ln -s ../security-manager.service %{buildroot}/%{_unitdir}/multi-user.target.wants/security-manager.service ln -s ../security-manager.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager.socket %clean @@ -136,11 +134,8 @@ fi %attr(755,root,root) %{_sysconfdir}/gumd/userdel.d/50_security-manager-remove.pre %{_libdir}/libsecurity-manager-commons.so.* -%attr(-,root,root) %{_unitdir}/multi-user.target.wants/security-manager.service -%attr(-,root,root) %{_unitdir}/security-manager.service -%attr(-,root,root) %{_unitdir}/security-manager.target -%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager.socket -%attr(-,root,root) %{_unitdir}/security-manager.socket +%attr(-,root,root) %{_unitdir}/security-manager.* +%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager.* %attr(-,root,root) %{TZ_SYS_SMACK}/app-rules-template.smack %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db-journal diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt index 66af5dd..90c0ec1 100644 --- a/systemd/CMakeLists.txt +++ b/systemd/CMakeLists.txt @@ -2,7 +2,6 @@ CONFIGURE_FILE(security-manager.service.in security-manager.service @ONLY) INSTALL(FILES security-manager.service - security-manager.target security-manager.socket DESTINATION ${SYSTEMD_INSTALL_DIR} diff --git a/systemd/security-manager.service.in b/systemd/security-manager.service.in index de58043..23fd1b2 100644 --- a/systemd/security-manager.service.in +++ b/systemd/security-manager.service.in @@ -4,8 +4,4 @@ Description=Start the security manager [Service] Type=notify ExecStart=@BIN_INSTALL_DIR@/security-manager - Sockets=security-manager.socket - -[Install] -WantedBy=multi-user.target diff --git a/systemd/security-manager.target b/systemd/security-manager.target deleted file mode 100644 index 8586718..0000000 --- a/systemd/security-manager.target +++ /dev/null @@ -1,4 +0,0 @@ -[Unit] -Description=security-manager sockets -DefaultDependencies=true - -- 2.7.4 From 144fe4bb52798d07efc936f895153d44bc1074ef Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Tue, 27 Jan 2015 16:28:48 +0100 Subject: [PATCH 10/16] Refactor off-line mode detection in client library Extract the detection into separate class for easy re-use in client library. The detection method will get additional logic soon, so having it in one place will be useful. Change-Id: I561b582eb044bf8f6aa71f090d790c00b7bb3273 Signed-off-by: Rafal Krypa --- src/client/CMakeLists.txt | 1 + src/client/client-offline.cpp | 58 ++++++++++++++++++++++++++++++++++ src/client/client-security-manager.cpp | 38 +++++++--------------- src/client/include/client-offline.h | 45 ++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 26 deletions(-) create mode 100644 src/client/client-offline.cpp create mode 100644 src/client/include/client-offline.h diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 077b393..4868c54 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -22,6 +22,7 @@ INCLUDE_DIRECTORIES( SET(CLIENT_SOURCES ${CLIENT_PATH}/client-security-manager.cpp ${CLIENT_PATH}/client-common.cpp + ${CLIENT_PATH}/client-offline.cpp ) ADD_LIBRARY(${TARGET_CLIENT} SHARED ${CLIENT_SOURCES}) diff --git a/src/client/client-offline.cpp b/src/client/client-offline.cpp new file mode 100644 index 0000000..115051a --- /dev/null +++ b/src/client/client-offline.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Rafal Krypa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file client-offline.cpp + * @author Rafal Krypa + * @version 1.0 + * @brief Helper class for client "off-line" mode detection + */ + +#include +#include "client-offline.h" + +namespace SecurityManager { + +ClientOffline::ClientOffline() +{ + offlineMode = false; + serviceLock = nullptr; + try { + serviceLock = new SecurityManager::FileLocker(SecurityManager::SERVICE_LOCK_FILE, false); + offlineMode = serviceLock->Locked(); + } catch (...) { + /* Ignore exceptions, assume on-line */ + } + + if (offlineMode) + LogInfo("Working in off-line mode."); + else + LogInfo("Working in on-line mode."); +} + +ClientOffline::~ClientOffline() +{ + if (serviceLock != nullptr) + delete serviceLock; +} + +bool ClientOffline::isOffline(void) +{ + return offlineMode; +} + +} // namespace SecurityManager diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index a11d4c4..f99dd89 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -44,9 +44,9 @@ #include #include #include -#include - #include +#include + /** * Mapping of lib_retcode error codes to theirs strings equivalents @@ -161,19 +161,11 @@ int security_manager_app_install(const app_inst_req *p_req) if (p_req->appId.empty() || p_req->pkgId.empty()) return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE; - bool offlineMode; int retval; - - try { - SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE); - if ((offlineMode = serviceLock.Locked())) { - LogInfo("Working in offline mode."); - retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid()); - } - } catch (const SecurityManager::FileLocker::Exception::Base &e) { - offlineMode = false; - } - if (!offlineMode) { + ClientOffline offlineMode; + if (offlineMode.isOffline()) { + retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid()); + } else { MessageBuffer send, recv; //put data into buffer @@ -555,22 +547,16 @@ SECURITY_MANAGER_API int security_manager_user_add(const user_req *p_req) { using namespace SecurityManager; - bool offlineMode; - MessageBuffer send, recv; if (!p_req) return SECURITY_MANAGER_ERROR_INPUT_PARAM; + return try_catch([&] { int retval; - try { - SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE); - if ((offlineMode = serviceLock.Locked())) { - LogInfo("Working in offline mode."); - retval = SecurityManager::ServiceImpl::userAdd(p_req->uid, p_req->utype, geteuid()); - } - } catch (const SecurityManager::FileLocker::Exception::Base &e) { - offlineMode = false; - } - if (!offlineMode) { + ClientOffline offlineMode; + if (offlineMode.isOffline()) { + retval = SecurityManager::ServiceImpl::userAdd(p_req->uid, p_req->utype, geteuid()); + } else { + MessageBuffer send, recv; //server is working //put data into buffer diff --git a/src/client/include/client-offline.h b/src/client/include/client-offline.h new file mode 100644 index 0000000..3f2e421 --- /dev/null +++ b/src/client/include/client-offline.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Rafal Krypa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file client-common.h + * @author Rafal Krypa + * @version 1.0 + * @brief Helper class for client "off-line" mode detection + */ + +#ifndef _SECURITY_MANAGER_OFFLINE_ +#define _SECURITY_MANAGER_OFFLINE_ + +#include + +namespace SecurityManager { + +class ClientOffline { +public: + ClientOffline(); + ~ClientOffline(); + bool isOffline(void); + +private: + bool offlineMode; + SecurityManager::FileLocker *serviceLock; +}; + +} // namespace SecurityManager + +#endif // _SECURITY_MANAGER_OFFLINE_ -- 2.7.4 From d672a29bd604d58f63bc0be98cd927b45834c41f Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Wed, 4 Feb 2015 17:58:14 +0100 Subject: [PATCH 11/16] Before running client in off-line mode, attempt to socket-activate the server Security-manager is started by systemd on socket-activation basis. This means that it won't start unless a client connects to its socket. But client library attempts to detect off-line mode by checking whether the service is already running. This leads to erroneous off-line runs when in fact a message should be sent over socket to activate the service. This change adds one more step to off-line mode detection. When the service isn't running, client will send a special NOOP message over socket. If systemd manages to activate security-manager service, normal on-line operation is then performed. Change-Id: I94b1b10af24e3b90d048fe1b96b8d870da785d8b Signed-off-by: Rafal Krypa --- src/client/client-offline.cpp | 20 +++++++++++++++++++- src/common/file-lock.cpp | 1 + src/common/include/file-lock.h | 2 -- src/common/include/protocols.h | 1 + src/server/service/service.cpp | 4 ++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/client/client-offline.cpp b/src/client/client-offline.cpp index 115051a..f926d77 100644 --- a/src/client/client-offline.cpp +++ b/src/client/client-offline.cpp @@ -22,6 +22,10 @@ * @brief Helper class for client "off-line" mode detection */ +#include +#include +#include +#include #include #include "client-offline.h" @@ -33,7 +37,21 @@ ClientOffline::ClientOffline() serviceLock = nullptr; try { serviceLock = new SecurityManager::FileLocker(SecurityManager::SERVICE_LOCK_FILE, false); - offlineMode = serviceLock->Locked(); + if (serviceLock->Locked()) { + int retval; + MessageBuffer send, recv; + + LogInfo("Service isn't running, try to trigger it via socket activation."); + serviceLock->Unlock(); + Serialization::Serialize(send, static_cast(SecurityModuleCall::NOOP)); + retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv); + if (retval != SECURITY_MANAGER_API_SUCCESS) { + LogInfo("Socket activation attempt failed."); + serviceLock->Lock(); + offlineMode = serviceLock->Locked(); + } else + LogInfo("Service seems to be running now."); + } } catch (...) { /* Ignore exceptions, assume on-line */ } diff --git a/src/common/file-lock.cpp b/src/common/file-lock.cpp index 1b9b0b8..36b2ccb 100644 --- a/src/common/file-lock.cpp +++ b/src/common/file-lock.cpp @@ -98,6 +98,7 @@ void FileLocker::Unlock() { if (m_locked) { m_flock.unlock(); + m_locked = false; LogDebug("Lock released."); } } diff --git a/src/common/include/file-lock.h b/src/common/include/file-lock.h index 620d757..604b019 100644 --- a/src/common/include/file-lock.h +++ b/src/common/include/file-lock.h @@ -50,8 +50,6 @@ public: ~FileLocker(); bool Locked(); - -protected: void Lock(); void Unlock(); diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 907a41a..20902ba 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -131,6 +131,7 @@ enum class SecurityModuleCall GET_POLICY, GET_CONF_POLICY_ADMIN, GET_CONF_POLICY_SELF, + NOOP = 0x90, }; } // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 7f75bed..ca0bf52 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -94,6 +94,10 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, SecurityModuleCall call_type = static_cast(call_type_int); switch (call_type) { + case SecurityModuleCall::NOOP: + LogDebug("call_type: SecurityModuleCall::NOOP"); + Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS); + break; case SecurityModuleCall::APP_INSTALL: LogDebug("call_type: SecurityModuleCall::APP_INSTALL"); processAppInstall(buffer, send, uid); -- 2.7.4 From 484106351e79456506dc046d6aafda777d744356 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 9 Jan 2015 18:16:28 +0100 Subject: [PATCH 12/16] Add missing rules for pkgId label Commit 626f947e0b changed labeling scheme to be appId based and introduced a new "~PKG~" template in the rules file. But the actual rules were not included in the template file. Change-Id: Idd5ababfb5b484811b75f2f764f6f7d77a77da1f Signed-off-by: Rafal Krypa --- app-rules-template.smack | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app-rules-template.smack b/app-rules-template.smack index a14da4f..1311169 100644 --- a/app-rules-template.smack +++ b/app-rules-template.smack @@ -5,6 +5,8 @@ System ~APP~ rwx ~APP~ System::Log rwxa ~APP~ _ l User ~APP~ rwxa +User ~PKG~ rwxat ~APP~ User wx ~APP~ User::Home rxl ~APP~ User::App::Shared rwxat +~APP~ ~PKG~ rwxat -- 2.7.4 From 4cae0fa1ae6c37b7ddca2c14cf48baf1c5a42e3d Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 9 Jan 2015 17:15:30 +0100 Subject: [PATCH 13/16] Ignore errors in supplementary group setup during app launch preparation Such errors might happen when launcher tries to launch an application that wasn't properly setup by the installer before. This should be supported to allow easier integration of security-manager into platform. Ignoring these errors won't cause any privilege escalation. Actually it might cause giving less privileges than necessary to the application. Change-Id: Ib8ba02a28404a25c541ba6daede9f68c864583cc Signed-off-by: Rafal Krypa --- src/client/client-security-manager.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index f99dd89..1e75744 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -402,8 +402,10 @@ int security_manager_set_process_groups_from_appid(const char *app_id) //receive response from server Deserialization::Deserialize(recv, retval); - if (retval != SECURITY_MANAGER_API_SUCCESS) + if (retval != SECURITY_MANAGER_API_SUCCESS) { + LogError("Failed to get list of groups from security-manager service. Error code: " << retval); return SECURITY_MANAGER_ERROR_UNKNOWN; + } //How many new groups? int newGroupsCnt; @@ -495,8 +497,10 @@ int security_manager_prepare_app(const char *app_id) return ret; ret = security_manager_set_process_groups_from_appid(app_id); - if (ret != SECURITY_MANAGER_SUCCESS) - return ret; + if (ret != SECURITY_MANAGER_SUCCESS) { + LogWarning("Unable to setup process groups for application. Privileges with direct access to resources will not work."); + ret = SECURITY_MANAGER_SUCCESS; + } ret = security_manager_drop_process_privileges(); return ret; -- 2.7.4 From 9d2f5358901d8a982ac138982c0c1938adbbcaad Mon Sep 17 00:00:00 2001 From: Michal Eljasiewicz Date: Mon, 26 Jan 2015 12:27:03 +0100 Subject: [PATCH 14/16] Wrapper for cynara_admin_list_policies_descriptions Change-Id: I6b07e4fb0b8e1395a3d867bcdecf1e79b3839772 Signed-off-by: Michal Eljasiewicz --- src/common/cynara.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/common/include/cynara.h | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 39b7e05..156ff26 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -205,7 +205,11 @@ static bool checkCynaraError(int result, const std::string &msg) } } +CynaraAdmin::TypeToDescriptionMap CynaraAdmin::TypeToDescription; +CynaraAdmin::DescriptionToTypeMap CynaraAdmin::DescriptionToType; + CynaraAdmin::CynaraAdmin() + : m_policyDescriptionsInitialized(false) { checkCynaraError( cynara_admin_initialize(&m_CynaraAdmin), @@ -380,6 +384,67 @@ void CynaraAdmin::EmptyBucket(const std::string &bucketName, bool recursive, con client + ", " + user + ", " + privilege); } +void CynaraAdmin::FetchCynaraPolicyDescriptions(bool forceRefresh) +{ + struct cynara_admin_policy_descr **descriptions = nullptr; + + if (!forceRefresh && m_policyDescriptionsInitialized) + return; + + // fetch + checkCynaraError( + cynara_admin_list_policies_descriptions(m_CynaraAdmin, &descriptions), + "Error while getting list of policies descriptions from Cynara."); + + if (descriptions[0] == nullptr) { + LogError("Fetching policies levels descriptions from Cynara returned empty list. " + "There should be at least 2 entries - Allow and Deny"); + return; + } + + // reset the state + m_policyDescriptionsInitialized = false; + DescriptionToType.clear(); + TypeToDescription.clear(); + + // extract strings + for (int i = 0; descriptions[i] != nullptr; i++) { + std::string descriptionName(descriptions[i]->name); + + DescriptionToType[descriptionName] = descriptions[i]->result; + TypeToDescription[descriptions[i]->result] = std::move(descriptionName); + + free(descriptions[i]->name); + free(descriptions[i]); + } + + free(descriptions); + + m_policyDescriptionsInitialized = true; +} + +void CynaraAdmin::ListPoliciesDescriptions(std::vector &policiesDescriptions) +{ + FetchCynaraPolicyDescriptions(false); + + for (auto it = TypeToDescription.rbegin(); it != TypeToDescription.rend(); ++it) + policiesDescriptions.push_back(it->second); +} + +std::string CynaraAdmin::convertToPolicyDescription(const int policyType, bool forceRefresh) +{ + FetchCynaraPolicyDescriptions(forceRefresh); + + return TypeToDescription.at(policyType); +} + +int CynaraAdmin::convertToPolicyType(const std::string &policy, bool forceRefresh) +{ + FetchCynaraPolicyDescriptions(forceRefresh); + + return DescriptionToType.at(policy); +} + Cynara::Cynara() { checkCynaraError( diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index ce103f0..1f37f96 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -91,6 +91,9 @@ public: typedef std::map BucketsMap; static BucketsMap Buckets; + typedef std::map TypeToDescriptionMap; + typedef std::map DescriptionToTypeMap; + virtual ~CynaraAdmin(); static CynaraAdmin &getInstance(); @@ -159,6 +162,43 @@ public: const std::string &privilege, std::vector &policies); + /** + * Wrapper for Cynara API function cynara_admin_list_policies_descriptions. + * It collects all policies descriptions, extracts names + * of policies and returns as std strings. Caller is responsible for clearing + * vector passed as argument. + * + * @param policiesDescriptions empty vector for policies descriptions. + */ + void ListPoliciesDescriptions(std::vector &policiesDescriptions); + + /** + * Function translates internal Cynara policy type integer to string + * description. Descriptions are retrieved from Cynara using + * ListPoliciesDescriptions() function. Caller can force refetching of + * descriptions list from Cynara on each call. + * + * @throws std::out_of_range + * + * @param policyType Cynara policy result type. + * @param forceRefresh switch to force refetching of descriptions from Cynara. + */ + std::string convertToPolicyDescription(const int policyType, bool forceRefresh = false); + + /** + * Function translates Cynara policy result string + * description to internal Cynara policy type integer. + * Descriptions are retrieved from Cynara using + * ListPoliciesDescriptions() function. Caller can force refetching of + * descriptions list from Cynara on each call. + * + * @throws std::out_of_range + * + * @param policy Cynara policy result string description. + * @param forceRefresh switch to force refetching of descriptions from Cynara. + */ + int convertToPolicyType(const std::string &policy, bool forceRefresh = false); + private: CynaraAdmin(); @@ -174,7 +214,18 @@ private: void EmptyBucket(const std::string &bucketName, bool recursive, const std::string &client, const std::string &user, const std::string &privilege); + /** + * Get Cynara policies result descriptions and cache them in std::map + * + * @param forceRefresh true if you want to reinitialize mappings + */ + void FetchCynaraPolicyDescriptions(bool forceRefresh = false); + struct cynara_admin *m_CynaraAdmin; + + static TypeToDescriptionMap TypeToDescription; + static DescriptionToTypeMap DescriptionToType; + bool m_policyDescriptionsInitialized; }; class Cynara -- 2.7.4 From 7d2626d9aa6367340fc367e35239aab0d5b9aa46 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 6 Feb 2015 12:05:19 +0100 Subject: [PATCH 15/16] Fix build break on x86_64 introduced in commit ed455f0c98 DPL has methods for deserializing int, but not long int. Changing size_t to plain int. Change-Id: If4d0e6c9d73e125f82a11f9ef0535f7e1968ca0d Signed-off-by: Rafal Krypa --- src/client/client-security-manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 1e75744..9a32631 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -711,16 +711,16 @@ static inline int security_manager_get_policy_internal( switch(retval) { case SECURITY_MANAGER_API_SUCCESS: { //extract and allocate buffers for privs policy entries - size_t entriesCnt = 0; + int entriesCnt = 0; policy_entry **entries = nullptr; Deserialization::Deserialize(recv, entriesCnt); try { entries = new policy_entry*[entriesCnt](); - for (size_t i = 0; i < entriesCnt; ++i) + for (int i = 0; i < entriesCnt; ++i) Deserialization::Deserialize(recv, entries[i]); } catch (...) { LogError("Error while parsing server response"); - for (size_t i = 0; i < entriesCnt; ++i) + for (int i = 0; i < entriesCnt; ++i) delete(entries[i]); delete entries; return SECURITY_MANAGER_ERROR_UNKNOWN; -- 2.7.4 From 057d49ed3dc3f54d1d72229ba2eebd8a8a5dd3e1 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Sat, 31 Jan 2015 15:29:34 +0100 Subject: [PATCH 16/16] Obtain smack label from socket during getting peer id by service This will be needed to validate peer application's privileges in cynara Change-Id: Id5c2dab311d3707a9c4cccf38623496bb5111826 Signed-off-by: Jan Cybulski --- src/server/service/service.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index ca0bf52..8a20ca4 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "protocols.h" #include "service.h" @@ -51,13 +52,20 @@ GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription() }; } -static bool getPeerID(int sock, uid_t &uid, pid_t &pid) { +static bool getPeerID(int sock, uid_t &uid, pid_t &pid, std::string &smackLabel) +{ struct ucred cr; socklen_t len = sizeof(cr); if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) { + char *smk; + ssize_t ret = smack_new_label_from_socket(sock, &smk); + if (ret < 0) + return false; + smackLabel = smk; uid = cr.uid; pid = cr.pid; + free(smk); return true; } @@ -79,9 +87,10 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, uid_t uid; pid_t pid; + std::string smackLabel; - if (!getPeerID(conn.sock, uid, pid)) { - LogError("Closing socket because of error: unable to get peer's uid and pid"); + if (!getPeerID(conn.sock, uid, pid, smackLabel)) { + LogError("Closing socket because of error: unable to get peer's uid, pid or smack label"); m_serviceManager->Close(conn); return false; } -- 2.7.4