From e4fdcb8c3066505d9a89cc9bce3e0917cd21444f Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 21 Nov 2014 00:45:05 +0100 Subject: [PATCH 01/16] Convert Cynara, CynaraAdmin and PrivilegeDb classes into singletons These classes are now used by the Service class to perform operations requested by clients. But they will be also needed by offline client implementation. Having them as private members of the Service class is no longer feasible. To keep their usage simple and available to the client as well, they are now used as singletons. Change-Id: I900a368ea14fbe61179c712b6e891f213ca61c5e Signed-off-by: Rafal Krypa --- src/common/cynara.cpp | 12 +++++++ src/common/include/cynara.h | 8 +++-- src/common/include/privilege_db.h | 16 ++++++---- src/common/privilege_db.cpp | 6 ++++ src/server/service/include/service.h | 2 -- src/server/service/service.cpp | 62 ++++++++++++++++++++---------------- 6 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 9ca8efc..36e79b2 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -134,6 +134,12 @@ CynaraAdmin::~CynaraAdmin() cynara_admin_finish(m_CynaraAdmin); } +CynaraAdmin &CynaraAdmin::getInstance() +{ + static CynaraAdmin cynaraAdmin; + return cynaraAdmin; +} + void CynaraAdmin::SetPolicies(const std::vector &policies) { std::vector pp_policies(policies.size() + 1); @@ -223,6 +229,12 @@ Cynara::~Cynara() cynara_finish(m_Cynara); } +Cynara &Cynara::getInstance() +{ + static Cynara cynara; + return cynara; +} + bool Cynara::check(const std::string &label, const std::string &privilege, const std::string &user, const std::string &session) { diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index c660a2e..ada3994 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -70,9 +70,10 @@ struct CynaraAdminPolicy : cynara_admin_policy class CynaraAdmin { public: - CynaraAdmin(); virtual ~CynaraAdmin(); + static CynaraAdmin &getInstance(); + /** * Update Cynara policies. * Caller must have permission to access Cynara administrative socket. @@ -104,15 +105,17 @@ public: const std::vector &newPrivileges); private: + CynaraAdmin(); struct cynara_admin *m_CynaraAdmin; }; class Cynara { public: - Cynara(); virtual ~Cynara(); + static Cynara &getInstance(); + /** * Ask Cynara for permission. * @@ -126,6 +129,7 @@ public: const std::string &user, const std::string &session); private: + Cynara(); struct cynara *m_Cynara; }; diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index b56f834..34a4ed1 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -60,6 +60,13 @@ class PrivilegeDb { */ private: + /** + * Constructor + * @exception DB::SqlConnection::Exception::IOError on problems with database access + * + */ + PrivilegeDb(const std::string &path = std::string(PRIVILEGE_DB_PATH)); + SecurityManager::DB::SqlConnection *mSqlConnection; const std::map Queries = { { QueryType::EGetPkgPrivileges, "SELECT DISTINCT privilege_name FROM app_privilege_view WHERE pkg_name=? AND uid=? ORDER BY privilege_name"}, @@ -91,15 +98,10 @@ public: DECLARE_EXCEPTION_TYPE(Base, InternalError) }; - /** - * Constructor - * @exception DB::SqlConnection::Exception::IOError on problems with database access - * - */ - PrivilegeDb(const std::string &path = std::string(PRIVILEGE_DB_PATH)); - ~PrivilegeDb(void); + static PrivilegeDb &getInstance(); + /** * Begin transaction * @exception DB::SqlConnection::Exception::InternalError on internal error diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index 6c8d1f3..e1c4b14 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -73,6 +73,12 @@ PrivilegeDb::~PrivilegeDb() delete mSqlConnection; } +PrivilegeDb &PrivilegeDb::getInstance() +{ + static PrivilegeDb privilegeDb; + return privilegeDb; +} + void PrivilegeDb::BeginTransaction(void) { try_catch([&] { diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 328043b..21bc19c 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -61,8 +61,6 @@ public: private: ConnectionInfoMap m_connectionInfoMap; - PrivilegeDb m_privilegeDb; - Cynara m_cynara; /** * Handle request from a client diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 32623c0..d4b27ca 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -311,25 +311,28 @@ bool Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_ LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); - m_privilegeDb.BeginTransaction(); - m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges); - m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew); - m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges); - m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges); + PrivilegeDb::getInstance().BeginTransaction(); + PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges); + PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew); + PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges); + PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges); CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, newPkgPrivileges); - m_privilegeDb.CommitTransaction(); + PrivilegeDb::getInstance().CommitTransaction(); LogDebug("Application installation commited to database"); + } catch (const PrivilegeDb::Exception::IOError &e) { + LogError("Cannot access application database: " << e.DumpToString()); + goto error_label; } catch (const PrivilegeDb::Exception::InternalError &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Error while saving application info to database: " << e.DumpToString()); goto error_label; } catch (const CynaraException::Base &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Error while setting Cynara rules for application: " << e.DumpToString()); goto error_label; } catch (const std::bad_alloc &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Memory allocation while setting Cynara rules for application: " << e.what()); goto error_label; } @@ -379,11 +382,11 @@ bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, ui try { std::vector oldPkgPrivileges, newPkgPrivileges; - m_privilegeDb.BeginTransaction(); - if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) { + PrivilegeDb::getInstance().BeginTransaction(); + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { LogWarning("Application " << appId << " not found in database while uninstalling"); - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); appExists = false; } else { @@ -395,25 +398,28 @@ bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, ui goto error_label; } - m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges); - m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector()); - m_privilegeDb.RemoveApplication(appId, uid, removePkg); - m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges); + PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector()); + PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges); CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, newPkgPrivileges); - m_privilegeDb.CommitTransaction(); + PrivilegeDb::getInstance().CommitTransaction(); LogDebug("Application uninstallation commited to database"); } + } catch (const PrivilegeDb::Exception::IOError &e) { + LogError("Cannot access application database: " << e.DumpToString()); + goto error_label; } catch (const PrivilegeDb::Exception::InternalError &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Error while removing application info from database: " << e.DumpToString()); goto error_label; } catch (const CynaraException::Base &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Error while setting Cynara rules for application: " << e.DumpToString()); goto error_label; } catch (const std::bad_alloc &e) { - m_privilegeDb.RollbackTransaction(); + PrivilegeDb::getInstance().RollbackTransaction(); LogError("Memory allocation while setting Cynara rules for application: " << e.what()); goto error_label; } @@ -448,14 +454,14 @@ bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send) LogDebug("appId: " << appId); try { - if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) { + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { LogWarning("Application " << appId << " not found in database"); Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT); return false; } else { LogDebug("pkgId: " << pkgId); } - } catch (const PrivilegeDb::Exception::InternalError &e) { + } catch (const PrivilegeDb::Exception::Base &e) { LogError("Error while getting pkgId from database: " << e.DumpToString()); Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); return false; @@ -481,7 +487,7 @@ bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, ui Deserialization::Deserialize(buffer, appId); LogDebug("appId: " << appId); - if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) { + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { LogWarning("Application " << appId << " not found in database"); Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT); return false; @@ -496,21 +502,21 @@ bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, ui LogDebug("smack label: " << smackLabel); std::vector privileges; - m_privilegeDb.GetPkgPrivileges(pkgId, uid, privileges); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges); /*there is also a need of checking, if privilege is granted to all users*/ size_t tmp = privileges.size(); - m_privilegeDb.GetPkgPrivileges(pkgId, getGlobalUserId(), privileges); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges); /*privileges needs to be sorted and with no duplications - for cynara sake*/ std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end()); privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() ); for (const auto &privilege : privileges) { std::vector gidsTmp; - m_privilegeDb.GetPrivilegeGroups(privilege, gidsTmp); + PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp); if (!gidsTmp.empty()) { LogDebug("Considering privilege " << privilege << " with " << gidsTmp.size() << " groups assigned"); - if (m_cynara.check(smackLabel, privilege, uidStr, pidStr)) { + if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) { for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) { struct group *grp = getgrnam(group.c_str()); @@ -525,7 +531,7 @@ bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, ui LogDebug("Cynara denied, not adding groups"); } } - } catch (const PrivilegeDb::Exception::InternalError &e) { + } catch (const PrivilegeDb::Exception::Base &e) { LogError("Database error: " << e.DumpToString()); Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); return false; -- 2.7.4 From 82abc7e44098a63300ecc2c4d9d40daf354a1a32 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 21 Nov 2014 11:55:07 +0100 Subject: [PATCH 02/16] Split service implementation logic away from the Service class The code implementing logic of Service methods is now available as separate functions. They will be available to both Service class and to the upcoming offline client implementation. Change-Id: Ib86af8c0f28dd7a1333e67ad0f2a4c968ff181cf Signed-off-by: Rafal Krypa --- src/common/CMakeLists.txt | 1 + src/common/include/service_impl.h | 87 ++++++++ src/common/service_impl.cpp | 365 ++++++++++++++++++++++++++++++++++ src/server/service/include/service.h | 12 +- src/server/service/service.cpp | 376 ++--------------------------------- 5 files changed, 479 insertions(+), 362 deletions(-) create mode 100644 src/common/include/service_impl.h create mode 100644 src/common/service_impl.cpp diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 68120d1..13bac8e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -50,6 +50,7 @@ SET(COMMON_SOURCES ${COMMON_PATH}/smack-labels.cpp ${COMMON_PATH}/smack-rules.cpp ${COMMON_PATH}/smack-check.cpp + ${COMMON_PATH}/service_impl.cpp ) ADD_LIBRARY(${TARGET_COMMON} SHARED ${COMMON_SOURCES}) diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h new file mode 100644 index 0000000..ba6a580 --- /dev/null +++ b/src/common/include/service_impl.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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 service_impl.h + * @author Rafal Krypa + * @brief Implementation of the service methods + */ + +#ifndef _SECURITY_MANAGER_SERVICE_IMPL_ +#define _SECURITY_MANAGER_SERVICE_IMPL_ + +#include +#include + +#include + +#include "security-manager.h" + +namespace SecurityManager { +namespace ServiceImpl { + +/** + * Process application installation request. + * + * @param[in] req installation request + * @param[in] uid id of the requesting user + * + * @return API return code, as defined in security-manager.h + */ +int appInstall(const app_inst_req &req, uid_t uid); + +/** + * Process application uninstallation request. + * + * @param[in] req uninstallation request + * @param[in] uid id of the requesting user + * + * @return API return code, as defined in security-manager.h + */ +int appUninstall(const std::string &appId, uid_t uid); + +/** + * Process package id query. + * Retrieves the package id associated with given application id. + * + * @param[in] appId application identifier + * @param[out] pkgId returned package identifier + * + * @return API return code, as defined in security-manager.h + */ +int getPkgId(const std::string &appId, std::string &pkgId); + +/** + * Process query for supplementary groups allowed for the application. + * For given appId and uid, calculate allowed privileges that give + * direct access to file system resources. For each permission Cynara will be + * queried. + * Returns set of group ids that are permitted. + * + * @param[in] appId application identifier + * @param[in] uid id of the requesting user + * @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 + */ +int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids); + +} /* namespace ServiceImpl */ +} /* namespace SecurityManager */ + +#endif /* _SECURITY_MANAGER_SERVICE_IMPL_ */ diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp new file mode 100644 index 0000000..360196f --- /dev/null +++ b/src/common/service_impl.cpp @@ -0,0 +1,365 @@ +/* + * Copyright (c) 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 service_impl.cpp + * @author Michal Witanowski + * @author Jacek Bukarewicz + * @author Rafal Krypa + * @brief Implementation of the service methods + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "protocols.h" +#include "privilege_db.h" +#include "cynara.h" +#include "smack-common.h" +#include "smack-rules.h" +#include "smack-labels.h" + +#include "service_impl.h" + +namespace SecurityManager { +namespace ServiceImpl { + +static uid_t getGlobalUserId(void) +{ + static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); + return globaluid; +} + +/** + * Unifies user data of apps installed for all users + * @param uid peer's uid - may be changed during process + * @param cynaraUserStr string to which cynara user parameter will be put + */ +static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr) +{ + static uid_t globaluid = getGlobalUserId(); + if (uid == 0 || uid == globaluid) { + uid = globaluid; + cynaraUserStr = CYNARA_ADMIN_WILDCARD; + } else { + cynaraUserStr = std::to_string(static_cast(uid)); + } +} +static inline bool isSubDir(const char *parent, const char *subdir) +{ + while (*parent && *subdir) + if (*parent++ != *subdir++) + return false; + + return (*subdir == '/'); +} + +static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid) +{ + struct passwd *pwd; + do { + errno = 0; + pwd = getpwuid(uid); + if (!pwd && errno != EINTR) { + LogError("getpwuid failed with '" << uid + << "' as paramter: " << strerror(errno)); + return false; + } + } while (!pwd); + + std::unique_ptr> home( + realpath(pwd->pw_dir, NULL), free); + if (!home.get()) { + LogError("realpath failed with '" << pwd->pw_dir + << "' as paramter: " << strerror(errno)); + return false; + } + + for (const auto &appPath : req.appPaths) { + std::unique_ptr> real_path( + realpath(appPath.first.c_str(), NULL), free); + if (!real_path.get()) { + LogError("realpath failed with '" << appPath.first.c_str() + << "' as paramter: " << strerror(errno)); + return false; + } + LogDebug("Requested path is '" << appPath.first.c_str() + << "'. User's HOME is '" << pwd->pw_dir << "'"); + if (!isSubDir(home.get(), real_path.get())) { + LogWarning("User's apps may have registered folders only in user's home dir"); + return false; + } + + app_install_path_type pathType = static_cast(appPath.second); + if (pathType == SECURITY_MANAGER_PATH_PUBLIC) { + LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path"); + return false; + } + } + return true; +} + +int appInstall(const app_inst_req &req, uid_t uid) +{ + bool pkgIdIsNew = false; + std::vector addedPermissions; + std::vector removedPermissions; + + std::string uidstr; + if ((!uid) && (req.uid)) + uid = req.uid; + checkGlobalUser(uid, uidstr); + + if (!installRequestAuthCheck(req, uid)) { + LogError("Request from uid " << uid << " for app installation denied"); + return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED; + } + + std::string smackLabel; + if (!generateAppLabel(req.pkgId, smackLabel)) { + LogError("Cannot generate Smack label for package: " << req.pkgId); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId + << ", generated smack label: " << smackLabel); + + // create null terminated array of strings for permissions + std::unique_ptr pp_permissions(new const char* [req.privileges.size() + 1]); + for (size_t i = 0; i < req.privileges.size(); ++i) { + LogDebug(" Permission = " << req.privileges[i]); + pp_permissions[i] = req.privileges[i].c_str(); + } + pp_permissions[req.privileges.size()] = nullptr; + + try { + std::vector oldPkgPrivileges, newPkgPrivileges; + + LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId + << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); + + PrivilegeDb::getInstance().BeginTransaction(); + PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges); + PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew); + PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges); + PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges); + CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, + newPkgPrivileges); + PrivilegeDb::getInstance().CommitTransaction(); + LogDebug("Application installation commited to database"); + } catch (const PrivilegeDb::Exception::IOError &e) { + LogError("Cannot access application database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const PrivilegeDb::Exception::InternalError &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while saving application info to database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const CynaraException::Base &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while setting Cynara rules for application: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const std::bad_alloc &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Memory allocation while setting Cynara rules for application: " << e.what()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + // register paths + for (const auto &appPath : req.appPaths) { + const std::string &path = appPath.first; + app_install_path_type pathType = static_cast(appPath.second); + int result = setupPath(req.pkgId, path, pathType); + + if (!result) { + LogError("setupPath() failed"); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + + if (pkgIdIsNew) { + LogDebug("Adding Smack rules for new pkgId " << req.pkgId); + if (!SmackRules::installPackageRules(req.pkgId)) { + LogError("Failed to apply package-specific smack rules"); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + + return SECURITY_MANAGER_API_SUCCESS; +} + +int appUninstall(const std::string &appId, uid_t uid) +{ + std::string pkgId; + std::string smackLabel; + bool appExists = true; + bool removePkg = false; + std::string uidstr; + checkGlobalUser(uid, uidstr); + + try { + std::vector oldPkgPrivileges, newPkgPrivileges; + + PrivilegeDb::getInstance().BeginTransaction(); + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { + LogWarning("Application " << appId << + " not found in database while uninstalling"); + PrivilegeDb::getInstance().RollbackTransaction(); + appExists = false; + } else { + + LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId + << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); + + if (!generateAppLabel(pkgId, smackLabel)) { + LogError("Cannot generate Smack label for package: " << pkgId); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges); + PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector()); + PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges); + CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, + newPkgPrivileges); + PrivilegeDb::getInstance().CommitTransaction(); + LogDebug("Application uninstallation commited to database"); + } + } catch (const PrivilegeDb::Exception::IOError &e) { + LogError("Cannot access application database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const PrivilegeDb::Exception::InternalError &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while removing application info from database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const CynaraException::Base &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while setting Cynara rules for application: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const std::bad_alloc &e) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Memory allocation while setting Cynara rules for application: " << e.what()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + if (appExists) { + + if (removePkg) { + LogDebug("Removing Smack rules for deleted pkgId " << pkgId); + if (!SmackRules::uninstallPackageRules(pkgId)) { + LogError("Error on uninstallation of package-specific smack rules"); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + } + + return SECURITY_MANAGER_API_SUCCESS; +} + +int getPkgId(const std::string &appId, std::string &pkgId) +{ + LogDebug("appId: " << appId); + + try { + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { + LogWarning("Application " << appId << " not found in database"); + return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT; + } else { + LogDebug("pkgId: " << pkgId); + } + } catch (const PrivilegeDb::Exception::Base &e) { + LogError("Error while getting pkgId from database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + return SECURITY_MANAGER_API_SUCCESS; +} + +int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids) +{ + try { + std::string pkgId; + std::string smackLabel; + std::string uidStr = std::to_string(uid); + std::string pidStr = std::to_string(pid); + + LogDebug("appId: " << appId); + + if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { + LogWarning("Application " << appId << " not found in database"); + return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT; + } + LogDebug("pkgId: " << pkgId); + + if (!generateAppLabel(pkgId, smackLabel)) { + LogError("Cannot generate Smack label for package: " << pkgId); + return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT; + } + LogDebug("smack label: " << smackLabel); + + std::vector privileges; + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges); + /*there is also a need of checking, if privilege is granted to all users*/ + size_t tmp = privileges.size(); + PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges); + /*privileges needs to be sorted and with no duplications - for cynara sake*/ + std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end()); + privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() ); + + for (const auto &privilege : privileges) { + std::vector gidsTmp; + PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp); + if (!gidsTmp.empty()) { + LogDebug("Considering privilege " << privilege << " with " << + gidsTmp.size() << " groups assigned"); + if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) { + for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) + { + struct group *grp = getgrnam(group.c_str()); + if (grp == NULL) { + LogError("No such group: " << group.c_str()); + return; + } + gids.insert(grp->gr_gid); + }); + LogDebug("Cynara allowed, adding groups"); + } else + LogDebug("Cynara denied, not adding groups"); + } + } + } catch (const PrivilegeDb::Exception::Base &e) { + LogError("Database error: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const CynaraException::Base &e) { + LogError("Error while querying Cynara for permissions: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation failed: " << e.what()); + return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; + } + + 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 21bc19c..88b4870 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -78,9 +78,8 @@ private: * @param buffer Raw received data buffer * @param send Raw data buffer to be sent * @param uid User's identifier for whom application will be installed - * @return true on success */ - bool processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); + void processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); /** * Process application uninstallation @@ -88,18 +87,16 @@ private: * @param buffer Raw received data buffer * @param send Raw data buffer to be sent * @param uid User's identifier for whom application will be uninstalled - * @return true on success */ - bool processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); + void processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); /** * Process getting package id from app id * * @param buffer Raw received data buffer * @param send Raw data buffer to be sent - * @return true on success */ - bool processGetPkgId(MessageBuffer &buffer, MessageBuffer &send); + void processGetPkgId(MessageBuffer &buffer, MessageBuffer &send); /** * Process getting permitted group ids for app id @@ -108,9 +105,8 @@ private: * @param send Raw data buffer to be sent * @param uid User's identifier for whom application will be launched * @param pid Process id in which application will be launched - * @return true on success */ - bool processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid); + void processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid); }; } // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index d4b27ca..5b83421 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -23,55 +23,19 @@ * @brief Implementation of security-manager service. */ -#include -#include -#include #include -#include - -#include -#include -#include #include #include -#include -#include "privilege_db.h" #include "protocols.h" -#include "security-manager.h" #include "service.h" -#include "smack-common.h" -#include "smack-rules.h" -#include "smack-labels.h" +#include "service_impl.h" namespace SecurityManager { const InterfaceID IFACE = 1; - - -static uid_t getGlobalUserId(void) { - static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER); - return globaluid; -} - -/** - * Unifies user data of apps installed for all users - * @param uid peer's uid - may be changed during process - * @param cynaraUserStr string to which cynara user parameter will be put - */ -static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr) -{ - static uid_t globaluid = getGlobalUserId(); - if (uid == 0 || uid == globaluid) { - uid = globaluid; - cynaraUserStr = CYNARA_ADMIN_WILDCARD; - } else { - cynaraUserStr = std::to_string(static_cast(uid)); - } -} - Service::Service() { } @@ -208,350 +172,54 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, return retval; } -static inline bool isSubDir(const char *parent, const char *subdir) -{ - while (*parent && *subdir) - if (*parent++ != *subdir++) - return false; - - return (*subdir == '/'); -} - -static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid) -{ - struct passwd *pwd; - do { - errno = 0; - pwd = getpwuid(uid); - if (!pwd && errno != EINTR) { - LogError("getpwuid failed with '" << uid - << "' as paramter: " << strerror(errno)); - return false; - } - } while (!pwd); - - std::unique_ptr> home( - realpath(pwd->pw_dir, NULL), free); - if (!home.get()) { - LogError("realpath failed with '" << pwd->pw_dir - << "' as paramter: " << strerror(errno)); - return false; - } - - for (const auto &appPath : req.appPaths) { - std::unique_ptr> real_path( - realpath(appPath.first.c_str(), NULL), free); - if (!real_path.get()) { - LogError("realpath failed with '" << appPath.first.c_str() - << "' as paramter: " << strerror(errno)); - return false; - } - LogDebug("Requested path is '" << appPath.first.c_str() - << "'. User's HOME is '" << pwd->pw_dir << "'"); - if (!isSubDir(home.get(), real_path.get())) { - LogWarning("User's apps may have registered folders only in user's home dir"); - return false; - } - - app_install_path_type pathType = static_cast(appPath.second); - if (pathType == SECURITY_MANAGER_PATH_PUBLIC) { - LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path"); - return false; - } - } - return true; -} - -bool Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) +void Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) { - bool pkgIdIsNew = false; - std::vector addedPermissions; - std::vector removedPermissions; - - // deserialize request data app_inst_req req; + Deserialization::Deserialize(buffer, req.appId); Deserialization::Deserialize(buffer, req.pkgId); Deserialization::Deserialize(buffer, req.privileges); Deserialization::Deserialize(buffer, req.appPaths); Deserialization::Deserialize(buffer, req.uid); - - std::string uidstr; - if ((!uid) && (req.uid)) - uid = req.uid; - checkGlobalUser(uid, uidstr); - - if(!installRequestAuthCheck(req, uid)) { - LogError("Request from uid " << uid << " for app installation denied"); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED); - return false; - } - - std::string smackLabel; - if (!generateAppLabel(req.pkgId, smackLabel)) { - LogError("Cannot generate Smack label for package: " << req.pkgId); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; - } - - LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId - << ", generated smack label: " << smackLabel); - - // create null terminated array of strings for permissions - std::unique_ptr pp_permissions(new const char* [req.privileges.size() + 1]); - for (size_t i = 0; i < req.privileges.size(); ++i) { - LogDebug(" Permission = " << req.privileges[i]); - pp_permissions[i] = req.privileges[i].c_str(); - } - pp_permissions[req.privileges.size()] = nullptr; - - try { - std::vector oldPkgPrivileges, newPkgPrivileges; - - LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId - << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); - - PrivilegeDb::getInstance().BeginTransaction(); - PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges); - PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew); - PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges); - PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges); - CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, - newPkgPrivileges); - PrivilegeDb::getInstance().CommitTransaction(); - LogDebug("Application installation commited to database"); - } catch (const PrivilegeDb::Exception::IOError &e) { - LogError("Cannot access application database: " << e.DumpToString()); - goto error_label; - } catch (const PrivilegeDb::Exception::InternalError &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Error while saving application info to database: " << e.DumpToString()); - goto error_label; - } catch (const CynaraException::Base &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Error while setting Cynara rules for application: " << e.DumpToString()); - goto error_label; - } catch (const std::bad_alloc &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Memory allocation while setting Cynara rules for application: " << e.what()); - goto error_label; - } - - // register paths - for (const auto &appPath : req.appPaths) { - const std::string &path = appPath.first; - app_install_path_type pathType = static_cast(appPath.second); - int result = setupPath(req.pkgId, path, pathType); - - if (!result) { - LogError("setupPath() failed"); - goto error_label; - } - } - - if (pkgIdIsNew) { - LogDebug("Adding Smack rules for new pkgId " << req.pkgId); - if (!SmackRules::installPackageRules(req.pkgId)) { - LogError("Failed to apply package-specific smack rules"); - goto error_label; - } - } - - // success - Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS); - return true; - -error_label: - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; + Serialization::Serialize(send, ServiceImpl::appInstall(req, uid)); } -bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) +void Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) { - // deserialize request data std::string appId; - std::string pkgId; - std::string smackLabel; - bool appExists = true; - bool removePkg = false; Deserialization::Deserialize(buffer, appId); - std::string uidstr; - checkGlobalUser(uid, uidstr); - - try { - std::vector oldPkgPrivileges, newPkgPrivileges; - - PrivilegeDb::getInstance().BeginTransaction(); - if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { - LogWarning("Application " << appId << - " not found in database while uninstalling"); - PrivilegeDb::getInstance().RollbackTransaction(); - appExists = false; - } else { - - LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId - << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); - - if (!generateAppLabel(pkgId, smackLabel)) { - LogError("Cannot generate Smack label for package: " << pkgId); - goto error_label; - } - - PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges); - PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector()); - PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg); - PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges); - CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges, - newPkgPrivileges); - PrivilegeDb::getInstance().CommitTransaction(); - LogDebug("Application uninstallation commited to database"); - } - } catch (const PrivilegeDb::Exception::IOError &e) { - LogError("Cannot access application database: " << e.DumpToString()); - goto error_label; - } catch (const PrivilegeDb::Exception::InternalError &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Error while removing application info from database: " << e.DumpToString()); - goto error_label; - } catch (const CynaraException::Base &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Error while setting Cynara rules for application: " << e.DumpToString()); - goto error_label; - } catch (const std::bad_alloc &e) { - PrivilegeDb::getInstance().RollbackTransaction(); - LogError("Memory allocation while setting Cynara rules for application: " << e.what()); - goto error_label; - } - - if (appExists) { - - if (removePkg) { - LogDebug("Removing Smack rules for deleted pkgId " << pkgId); - if (!SmackRules::uninstallPackageRules(pkgId)) { - LogError("Error on uninstallation of package-specific smack rules"); - goto error_label; - } - } - } - - // success - Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS); - return true; - -error_label: - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; + Serialization::Serialize(send, ServiceImpl::appUninstall(appId, uid)); } -bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send) +void Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send) { - // deserialize request data std::string appId; std::string pkgId; + int ret; Deserialization::Deserialize(buffer, appId); - LogDebug("appId: " << appId); - - try { - if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { - LogWarning("Application " << appId << " not found in database"); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT); - return false; - } else { - LogDebug("pkgId: " << pkgId); - } - } catch (const PrivilegeDb::Exception::Base &e) { - LogError("Error while getting pkgId from database: " << e.DumpToString()); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; - } - - // success - Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS); - Serialization::Serialize(send, pkgId); - return true; + ret = ServiceImpl::getPkgId(appId, pkgId); + Serialization::Serialize(send, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Serialization::Serialize(send, pkgId); } -bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid) +void Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid) { + std::string appId; std::unordered_set gids; + int ret; - try { - std::string appId; - std::string pkgId; - std::string smackLabel; - std::string uidStr = std::to_string(uid); - std::string pidStr = std::to_string(pid); - - Deserialization::Deserialize(buffer, appId); - LogDebug("appId: " << appId); - - if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) { - LogWarning("Application " << appId << " not found in database"); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT); - return false; - } - LogDebug("pkgId: " << pkgId); - - if (!generateAppLabel(pkgId, smackLabel)) { - LogError("Cannot generate Smack label for package: " << pkgId); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT); - return false; - } - LogDebug("smack label: " << smackLabel); - - std::vector privileges; - PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges); - /*there is also a need of checking, if privilege is granted to all users*/ - size_t tmp = privileges.size(); - PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges); - /*privileges needs to be sorted and with no duplications - for cynara sake*/ - std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end()); - privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() ); - - for (const auto &privilege : privileges) { - std::vector gidsTmp; - PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp); - if (!gidsTmp.empty()) { - LogDebug("Considering privilege " << privilege << " with " << - gidsTmp.size() << " groups assigned"); - if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) { - for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) - { - struct group *grp = getgrnam(group.c_str()); - if (grp == NULL) { - LogError("No such group: " << group.c_str()); - return; - } - gids.insert(grp->gr_gid); - }); - LogDebug("Cynara allowed, adding groups"); - } else - LogDebug("Cynara denied, not adding groups"); - } + Deserialization::Deserialize(buffer, appId); + ret = ServiceImpl::getAppGroups(appId, uid, pid, gids); + Serialization::Serialize(send, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) { + Serialization::Serialize(send, static_cast(gids.size())); + for (const auto &gid : gids) { + Serialization::Serialize(send, gid); } - } catch (const PrivilegeDb::Exception::Base &e) { - LogError("Database error: " << e.DumpToString()); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; - } catch (const CynaraException::Base &e) { - LogError("Error while querying Cynara for permissions: " << e.DumpToString()); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR); - return false; - } catch (const std::bad_alloc &e) { - LogError("Memory allocation failed: " << e.what()); - Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY); - return false; - } - - // success - Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS); - Serialization::Serialize(send, static_cast(gids.size())); - for (const auto &gid : gids) { - Serialization::Serialize(send, gid); } - return true; } -- 2.7.4 From 1e0c092d4bc9d38355c14feb1a79b5605812e174 Mon Sep 17 00:00:00 2001 From: Sebastian Grabowski Date: Thu, 27 Nov 2014 16:15:23 +0100 Subject: [PATCH 03/16] Typo fixes in installRequestAuthCheck Changed 'paramter' to 'parameter' in installRequestAuthCheck function. Change-Id: Iba5e3f6c3388c9faea8a326b7bf8e1b4ba48b0fa Signed-off-by: Sebastian Grabowski --- src/common/service_impl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 360196f..f2a234c 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -83,7 +83,7 @@ static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid) pwd = getpwuid(uid); if (!pwd && errno != EINTR) { LogError("getpwuid failed with '" << uid - << "' as paramter: " << strerror(errno)); + << "' as parameter: " << strerror(errno)); return false; } } while (!pwd); @@ -92,7 +92,7 @@ static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid) realpath(pwd->pw_dir, NULL), free); if (!home.get()) { LogError("realpath failed with '" << pwd->pw_dir - << "' as paramter: " << strerror(errno)); + << "' as parameter: " << strerror(errno)); return false; } @@ -101,7 +101,7 @@ static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid) realpath(appPath.first.c_str(), NULL), free); if (!real_path.get()) { LogError("realpath failed with '" << appPath.first.c_str() - << "' as paramter: " << strerror(errno)); + << "' as parameter: " << strerror(errno)); return false; } LogDebug("Requested path is '" << appPath.first.c_str() -- 2.7.4 From fa7952dd72f089f2ab720f729d89acfea6490d29 Mon Sep 17 00:00:00 2001 From: Sebastian Grabowski Date: Wed, 5 Nov 2014 12:27:23 +0100 Subject: [PATCH 04/16] Added support for offline applications installations mode Added support for offline mode in AppInstall function. Moreover, security_manager_app_install will now check if it can get a file lock on /run/lock/security-manager.lock. If it can it will do installation request in offline mode. Otherwise, it will send installation request to security-manager service. Change-Id: Ie8b8f98b1fa0d3021ae76ee7aa4e7416e3ed73b9 Signed-off-by: Sebastian Grabowski --- src/client/client-security-manager.cpp | 49 +++++++++++++++++++++++----------- src/common/service_impl.cpp | 12 +++++++-- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 14fbcbf..a4fa36a 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include @@ -60,7 +62,7 @@ int security_manager_app_inst_req_new(app_inst_req **pp_req) } catch (std::bad_alloc& ex) { return SECURITY_MANAGER_ERROR_MEMORY; } - (*pp_req)->uid = 0; + (*pp_req)->uid = geteuid(); return SECURITY_MANAGER_SUCCESS; } @@ -131,7 +133,6 @@ SECURITY_MANAGER_API int security_manager_app_install(const app_inst_req *p_req) { using namespace SecurityManager; - MessageBuffer send, recv; return try_catch([&] { //checking parameters @@ -140,23 +141,39 @@ 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; - //put data into buffer - Serialization::Serialize(send, (int)SecurityModuleCall::APP_INSTALL); - Serialization::Serialize(send, p_req->appId); - Serialization::Serialize(send, p_req->pkgId); - Serialization::Serialize(send, p_req->privileges); - Serialization::Serialize(send, p_req->appPaths); - Serialization::Serialize(send, p_req->uid); + bool offlineMode; + int retval; - //send buffer 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; + 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) { + MessageBuffer send, recv; + + //put data into buffer + Serialization::Serialize(send, (int)SecurityModuleCall::APP_INSTALL); + Serialization::Serialize(send, p_req->appId); + Serialization::Serialize(send, p_req->pkgId); + Serialization::Serialize(send, p_req->privileges); + Serialization::Serialize(send, p_req->appPaths); + Serialization::Serialize(send, p_req->uid); + + //send buffer to server + 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); + //receive response from server + Deserialization::Deserialize(recv, retval); + } switch(retval) { case SECURITY_MANAGER_API_SUCCESS: return SECURITY_MANAGER_SUCCESS; diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index f2a234c..fe7982d 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -127,8 +127,16 @@ int appInstall(const app_inst_req &req, uid_t uid) std::vector removedPermissions; std::string uidstr; - if ((!uid) && (req.uid)) - uid = req.uid; + if (uid) { + if (uid != req.uid) { + LogError("User " << uid << + " is denied to install application for user " << req.uid); + return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED; + } + } else { + if (req.uid) + uid = req.uid; + } checkGlobalUser(uid, uidstr); if (!installRequestAuthCheck(req, uid)) { -- 2.7.4 From c24b51ec1f9a164a16d3bcfb02ada68411abd723 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Mon, 24 Nov 2014 15:44:18 +0100 Subject: [PATCH 05/16] Database access function obtaining apps of a certain user This will be used during user removal in security-manager. Change-Id: I524c9bf2da936054b7c1b597d7e4eaf879872912 Signed-off-by: Jan Cybulski --- src/common/include/privilege_db.h | 12 ++++++++++++ src/common/privilege_db.cpp | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index 34a4ed1..a95ade8 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -52,6 +52,7 @@ enum class QueryType { EPkgIdExists, EGetPkgId, EGetPrivilegeGroups, + EGetUserApps, }; class PrivilegeDb { @@ -77,6 +78,7 @@ private: { QueryType::EPkgIdExists, "SELECT * FROM pkg WHERE name=?" }, { QueryType::EGetPkgId, " SELECT pkg_name FROM app_pkg_view WHERE app_name = ?" }, { QueryType::EGetPrivilegeGroups, " SELECT name FROM privilege_group_view WHERE privilege_name = ?" }, + { QueryType::EGetUserApps, "SELECT name FROM app WHERE uid=?" }, }; /** @@ -197,6 +199,16 @@ public: void GetPrivilegeGroups(const std::string &privilege, std::vector &grp_names); + /** + * Retrieve list of apps assigned to user + * + * @param uid - user identifier + * @param[out] apps - list of apps assigned to user, + * this parameter do not need to be empty, but + * it is being overwritten during function call. + * @exception DB::SqlConnection::Exception::InternalError on internal error + */ + void GetUserApps(uid_t uid, std::vector &apps); }; } //namespace SecurityManager diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index e1c4b14..ac83ce6 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -262,5 +262,21 @@ void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege, }); } +void PrivilegeDb::GetUserApps(uid_t uid, std::vector &apps) +{ + try_catch([&] { + DB::SqlConnection::DataCommandAutoPtr command = + mSqlConnection->PrepareDataCommand( + Queries.at(QueryType::EGetUserApps)); + command->BindInteger(1, static_cast(uid)); + apps.clear(); + while (command->Step()) { + std::string app = command->GetColumnString(0); + LogDebug("User " << uid << " has app " << app << " installed"); + apps.push_back(app); + }; + }); +} + } //namespace SecurityManager -- 2.7.4 From 5881ce138667320a0ac8d9d04a8bdd32f4d7149d Mon Sep 17 00:00:00 2001 From: Sebastian Grabowski Date: Mon, 27 Oct 2014 14:22:02 +0100 Subject: [PATCH 06/16] Added security-manager-cmd application. The purpose of this application is to have an offline tool that will do some commands in offline mode i.e.: when security-manager service cannot be run. For now, only install command is supported which should be the equivalent of security_manager_app_install function. Change-Id: Ia9ef60b1a335650fea90c02e5fdd76ac48030f84 Signed-off-by: Sebastian Grabowski --- packaging/security-manager.spec | 1 + src/CMakeLists.txt | 3 + src/cmd/CMakeLists.txt | 30 ++++ src/cmd/security-manager-cmd.cpp | 304 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 src/cmd/CMakeLists.txt create mode 100644 src/cmd/security-manager-cmd.cpp diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 2a3c653..cd68faa 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -119,6 +119,7 @@ fi %manifest security-manager.manifest %defattr(-,root,root,-) %attr(755,root,root) %{_bindir}/security-manager +%attr(755,root,root) %{_bindir}/security-manager-cmd %{_libdir}/libsecurity-manager-commons.so.* %attr(-,root,root) %{_unitdir}/multi-user.target.wants/security-manager.service %attr(-,root,root) %{_unitdir}/security-manager.service diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01f2aa5..30d65cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,13 +3,16 @@ SET(COMMON_PATH ${PROJECT_SOURCE_DIR}/src/common) SET(CLIENT_PATH ${PROJECT_SOURCE_DIR}/src/client) SET(SERVER_PATH ${PROJECT_SOURCE_DIR}/src/server) SET(DPL_PATH ${PROJECT_SOURCE_DIR}/src/dpl) +SET(CMD_PATH ${PROJECT_SOURCE_DIR}/src/cmd) SET(TARGET_SERVER "security-manager") SET(TARGET_CLIENT "security-manager-client") SET(TARGET_COMMON "security-manager-commons") SET(TARGET_DB ".security-manager.db") +SET(TARGET_CMD "security-manager-cmd") ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(common) ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(server) +ADD_SUBDIRECTORY(cmd) diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt new file mode 100644 index 0000000..d588676 --- /dev/null +++ b/src/cmd/CMakeLists.txt @@ -0,0 +1,30 @@ +FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options) + +INCLUDE_DIRECTORIES(SYSTEM + ${Boost_INCLUDE_DIRS} + ) + +INCLUDE_DIRECTORIES( + ${INCLUDE_PATH} + ${COMMON_PATH}/include + ${DPL_PATH}/core/include + ${DPL_PATH}/log/include + ) + +SET(CMD_SOURCES + ${CMD_PATH}/security-manager-cmd.cpp + ) + +ADD_EXECUTABLE(${TARGET_CMD} ${CMD_SOURCES}) + +SET_TARGET_PROPERTIES(${TARGET_CMD} + PROPERTIES + COMPILE_FLAGS "-D_GNU_SOURCE -fvisibility=hidden") + +TARGET_LINK_LIBRARIES(${TARGET_CMD} + ${TARGET_COMMON} + ${TARGET_CLIENT} + ${Boost_LIBRARIES} + ) + +INSTALL(TARGETS ${TARGET_CMD} DESTINATION ${BIN_INSTALL_DIR}) diff --git a/src/cmd/security-manager-cmd.cpp b/src/cmd/security-manager-cmd.cpp new file mode 100644 index 0000000..ec7b680 --- /dev/null +++ b/src/cmd/security-manager-cmd.cpp @@ -0,0 +1,304 @@ +/* + * 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 service-manager-cmd.cpp + * @author Sebastian Grabowski (s.grabowski@samsung.com) + * @version 1.0 + * @brief Implementation of security-manager-cmd tool for offline mode + */ +/* vim: set ts=4 et sw=4 tw=78 : */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +namespace po = boost::program_options; + +IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem); + +static std::map app_install_path_type_map = { + {"private", SECURITY_MANAGER_PATH_PRIVATE}, + {"public", SECURITY_MANAGER_PATH_PUBLIC}, + {"public_ro", SECURITY_MANAGER_PATH_PUBLIC_RO} +}; + +static po::options_description getGenericOptions() +{ + po::options_description opts("Generic options"); + opts.add_options() + ("help,h", "produce help message") + ("install,i", "install an application") + ; + return opts; +} + +static po::options_description getInstallOptions() +{ + po::options_description opts("Install options"); + opts.add_options() + ("app,a", po::value()->required(), + "application name (required)") + ("pkg,g", po::value()->required(), + "package name for the application (required)") + /* + * multitoken: Specifies that the value can span multiple tokens. + * So it is possible to pass values to an option like + * this: + * --path=/home/user dirtype + * --path /home/user dirtype + * --path="/home/user" dirtype + */ + ("path,p", po::value< std::vector >()->multitoken(), + "path for setting smack labels (may occur more than once).\n" + "Format: --path \n" + " where is: \tprivate, public, public_ro\n" + "example:\n" + " \t--path=/home/user/app private") + ("privilege,s", po::value< std::vector >(), + "privilege for the application (may occur more than once)") + ("uid,u", po::value()->required(), + "user identifier number (required)") + ; + return opts; +} + +static po::options_description getAllOptions() +{ + po::options_description opts("Allowed options"); + opts.add(getGenericOptions()).add(getInstallOptions()); + return opts; +} + +static void usage(std::string name) +{ + using namespace std; + + cout << endl << name << " usage:" << endl; + cout << endl << getAllOptions() << endl << endl; +} + +static bool parseCommandOptions(int argc, char *argv[], std::string cmd, + po::options_description opts, + po::variables_map &vm) +{ + bool ret = false; + + try { + const po::positional_options_description p; + /* style options: + * unix_style: The more-or-less traditional unix style. It looks as + * follows: unix_style = (allow_short | short_allow_adjacent | + * short_allow_next | allow_long | + * long_allow_adjacent | long_allow_next | + * allow_sticky | allow_guessing | + * allow_dash_for_short) + * allow_long_disguise: Allow long options with single option starting + * character, e.g -foo=10 + * allow_guessing: Allow abbreviated spellings for long options, if + * they unambiguously identify long option. No long + * option name should be prefix of other long option name if + * guessing is in effect. + * allow_short: Alow "- &paths, + struct app_inst_req &req) +{ + if (paths.size() & 1) { + std::cout << "Wrong number of tokens was given for path option." << + std::endl; + LogDebug("Wrong paths size: " << paths.size()); + return false; + } + req.appPaths.clear(); + for (std::vector::size_type i = 1; i < paths.size(); i += 2) { + app_install_path_type pathType; + LogDebug("path: " << paths[i - 1]); + try { + pathType = app_install_path_type_map.at(paths[i]); + } catch (const std::out_of_range &e) { + std::cout << "Invalid path type found." << std::endl; + LogError("Invalid path type found."); + req.appPaths.clear(); + return false; + } + LogDebug("path type: " << pathType << " (" << paths[i] << ")"); + req.appPaths.push_back(std::make_pair(paths[i - 1], pathType)); + } + return (!req.appPaths.empty()); +} + +static bool parseInstallOptions(int argc, char *argv[], + struct app_inst_req &req, + po::variables_map &vm) +{ + bool ret; + ret = parseCommandOptions(argc, argv, "install", getInstallOptions(), vm); + if (!ret) + return ret; + try { + if (vm.count("app")) + req.appId = vm["app"].as(); + if (vm.count("pkg")) + req.pkgId = vm["pkg"].as(); + if (vm.count("path")) { + const std::vector paths = + vm["path"].as >(); + if (!loadPaths(paths, req)) { + std::cout << "Error in parsing path arguments." << std::endl; + LogError("Error in parsing path arguments."); + return false; + } + } + if (vm.count("privilege")) { + req.privileges = vm["privilege"].as >(); + if (req.privileges.empty()) { + std::cout << "Error in parsing privilege arguments." << std::endl; + LogError("Error in parsing privilege arguments."); + return false; + } +#ifdef BUILD_TYPE_DEBUG + LogDebug("Passed privileges:"); + for (const auto &p : req.privileges) { + LogDebug(" " << p); + } +#endif + } + if (vm.count("uid")) + req.uid = vm["uid"].as(); + } catch (const std::exception &e) { + std::cout << "Error while parsing install arguments: " << e.what() << + std::endl; + LogError("Error while parsing install arguments: " << e.what()); + ret = false; + } + return ret; +} + +static int installApp(const struct app_inst_req &req) +{ + int ret = EXIT_FAILURE; + + ret = security_manager_app_install(&req); + if (SECURITY_MANAGER_SUCCESS == ret) { + std::cout << "Application " << req.appId << + " installed successfully." << std::endl; + LogDebug("Application " << req.appId << + " installed successfully."); + } else { + std::cout << "Failed to install " << req.appId << + " application. Return code: " << ret << + std::endl; + LogDebug("Failed to install " << req.appId << + " application. Return code: " << ret); + } + return ret; +} + +int main(int argc, char *argv[]) +{ + po::variables_map vm; + + UNHANDLED_EXCEPTION_HANDLER_BEGIN + { + SecurityManager::Singleton::Instance().SetTag("SECURITY_MANAGER_INSTALLER"); + + LogDebug("argc: " << argc); + for (int i = 0; i < argc; ++i) + LogDebug("argv [" << i << "]: " << argv[i]); + if (argc < 2) { + std::cout << "Missing arguments." << std::endl; + usage(std::string(argv[0])); + return EXIT_FAILURE; + } + po::store(po::command_line_parser(argc, argv). + options(getGenericOptions()).allow_unregistered().run(), + vm); + if (vm.count("help")) { + usage(std::string(argv[0])); + return EXIT_SUCCESS; + } + LogDebug("Generic arguments has been parsed."); + + if (vm.count("install")) { + struct app_inst_req *req = nullptr; + LogDebug("Install command."); + if (security_manager_app_inst_req_new(&req) != SECURITY_MANAGER_SUCCESS) + return EXIT_FAILURE; + if (parseInstallOptions(argc, argv, *req, vm)) + return installApp(*req); + else + return EXIT_FAILURE; + } else { + std::cout << "No command argument was given." << std::endl; + usage(std::string(argv[0])); + return EXIT_FAILURE; + } + } + UNHANDLED_EXCEPTION_HANDLER_END + + return EXIT_FAILURE; +} + -- 2.7.4 From d43e9ed60fc7052e193a4f0207fc04ee3d646432 Mon Sep 17 00:00:00 2001 From: Sebastian Grabowski Date: Mon, 1 Dec 2014 16:26:56 +0100 Subject: [PATCH 07/16] Added security_manager_strerror function. This function translates lib_retcode(s) to a string describing given error that occured in security-manager. Change-Id: Ied57ff8c27a972123b28714ebc25efe143c6d64c Signed-off-by: Sebastian Grabowski --- src/client/client-security-manager.cpp | 21 +++++++++++++++++++++ src/cmd/security-manager-cmd.cpp | 11 ++++++----- src/include/security-manager.h | 8 ++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index a4fa36a..1e03d36 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -49,7 +49,28 @@ #include +/** + * Mapping of lib_retcode error codes to theirs strings equivalents + */ +static std::map lib_retcode_string_map = { + {SECURITY_MANAGER_SUCCESS, "Success"}, + {SECURITY_MANAGER_ERROR_UNKNOWN, "Unknown error"}, + {SECURITY_MANAGER_ERROR_INPUT_PARAM, "Invalid function parameter was given"}, + {SECURITY_MANAGER_ERROR_MEMORY, "Memory allocation error"}, + {SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE, "Incomplete data in application request"}, + {SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED, "User does not have sufficient " + "rigths to perform an operation"} +}; +SECURITY_MANAGER_API +const char *security_manager_strerror(enum lib_retcode rc) +{ + try { + return lib_retcode_string_map.at(rc).c_str(); + } catch (const std::out_of_range &e) { + return "Unknown error code"; + } +} SECURITY_MANAGER_API int security_manager_app_inst_req_new(app_inst_req **pp_req) diff --git a/src/cmd/security-manager-cmd.cpp b/src/cmd/security-manager-cmd.cpp index ec7b680..c615d12 100644 --- a/src/cmd/security-manager-cmd.cpp +++ b/src/cmd/security-manager-cmd.cpp @@ -248,11 +248,12 @@ static int installApp(const struct app_inst_req &req) LogDebug("Application " << req.appId << " installed successfully."); } else { - std::cout << "Failed to install " << req.appId << - " application. Return code: " << ret << - std::endl; - LogDebug("Failed to install " << req.appId << - " application. Return code: " << ret); + std::cout << "Failed to install " << req.appId << " application: " << + security_manager_strerror(static_cast(ret)) << + " (" << ret << ")." << std::endl; + LogError("Failed to install " << req.appId << " application: " << + security_manager_strerror(static_cast(ret)) << + " (" << ret << ")." << std::endl); } return ret; } diff --git a/src/include/security-manager.h b/src/include/security-manager.h index c06b2fb..36028c2 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -60,6 +60,14 @@ enum app_install_path_type { struct app_inst_req; typedef struct app_inst_req app_inst_req; +/** + * This function translates lib_retcode error codes to strings describing + * errors. + * @param[in] rc error code of lib_retcode type + * @return string describing error for error code + */ +const char *security_manager_strerror(enum lib_retcode rc); + /* * This function is responsible for initialize app_inst_req data structure * It uses dynamic allocation inside and user responsibility is to call -- 2.7.4 From 558aa5538aadae7a8301c6163c7d635d17796aaa Mon Sep 17 00:00:00 2001 From: Marcin Lis Date: Thu, 27 Nov 2014 14:06:08 +0100 Subject: [PATCH 08/16] Prepare database queries during PrivilegeDb singleton init Avoid too many sqlite3_prepare_v2 calls, which take many cpu cycles to complete. SQLite statements may be prepared once when DB object is created. Change-Id: I99e4fd3fea63fd61396c9f7b2c3b13539f312d48 Signed-off-by: Marcin Lis --- src/common/include/privilege_db.h | 14 ++++++ src/common/privilege_db.cpp | 76 +++++++++++++++++------------- src/dpl/db/include/dpl/db/sql_connection.h | 2 +- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index a95ade8..1df7723 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -82,6 +82,20 @@ private: }; /** + * Container for initialized DataCommands, prepared for binding. + */ + std::vector m_commands; + + /** + * Fills empty m_commands map with sql commands prepared for binding. + * + * Because the "sqlite3_prepare_v2" function takes many cpu cycles, the PrivilegeDb + * is optimized to call it only once for one query type. + * Designed to be used in the singleton contructor. + */ + void initDataCommands(); + + /** * Check if pkgId is already registered in database * * @param pkgId - package identifier diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index ac83ce6..cca5aaa 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -60,6 +60,7 @@ PrivilegeDb::PrivilegeDb(const std::string &path) mSqlConnection = new DB::SqlConnection(path, DB::SqlConnection::Flag::None, DB::SqlConnection::Flag::RW); + initDataCommands(); } catch (DB::SqlConnection::Exception::Base &e) { LogError("Database initialization error: " << e.DumpToString()); ThrowMsg(PrivilegeDb::Exception::IOError, @@ -68,6 +69,13 @@ PrivilegeDb::PrivilegeDb(const std::string &path) }; } +void PrivilegeDb::initDataCommands() +{ + for (auto &it : Queries) { + m_commands.push_back(mSqlConnection->PrepareDataCommand(it.second)); + } +} + PrivilegeDb::~PrivilegeDb() { delete mSqlConnection; @@ -103,26 +111,22 @@ void PrivilegeDb::RollbackTransaction(void) bool PrivilegeDb::PkgIdExists(const std::string &pkgId) { return try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::EPkgIdExists)); - command->BindString(1, pkgId.c_str()); - if (command->Step()) { - // pkgId found in the database - command->Reset(); - return true; - }; + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EPkgIdExists)); - // pkgId not found in the database - return false; + command->Reset(); + command->BindString(1, pkgId.c_str()); + return command->Step(); }); } bool PrivilegeDb::GetAppPkgId(const std::string &appId, std::string &pkgId) { return try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand(Queries.at(QueryType::EGetPkgId)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EGetPkgId)); + + command->Reset(); command->BindString(1, appId.c_str()); if (!command->Step()) { @@ -143,10 +147,10 @@ void PrivilegeDb::AddApplication(const std::string &appId, pkgIdIsNew = !(this->PkgIdExists(pkgId)); try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::EAddApplication)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EAddApplication)); + command->Reset(); command->BindString(1, appId.c_str()); command->BindString(2, pkgId.c_str()); command->BindInteger(3, static_cast(uid)); @@ -156,7 +160,6 @@ void PrivilegeDb::AddApplication(const std::string &appId, Queries.at(QueryType::EAddApplication)); }; - command->Reset(); LogDebug("Added appId: " << appId << ", pkgId: " << pkgId); }); } @@ -171,10 +174,10 @@ void PrivilegeDb::RemoveApplication(const std::string &appId, uid_t uid, return; } - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::ERemoveApplication)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::ERemoveApplication)); + command->Reset(); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -183,7 +186,6 @@ void PrivilegeDb::RemoveApplication(const std::string &appId, uid_t uid, Queries.at(QueryType::ERemoveApplication)); }; - command->Reset(); LogDebug("Removed appId: " << appId); pkgIdIsNoMore = !(this->PkgIdExists(pkgId)); @@ -194,9 +196,10 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId, uid_t uid, std::vector ¤tPrivileges) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::EGetPkgPrivileges)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EGetPkgPrivileges)); + + command->Reset(); command->BindString(1, pkgId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -211,9 +214,10 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId, uid_t uid, void PrivilegeDb::RemoveAppPrivileges(const std::string &appId, uid_t uid) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand(Queries.at(QueryType::ERemoveAppPrivileges)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::ERemoveAppPrivileges)); + command->Reset(); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); if (command->Step()) { @@ -229,8 +233,10 @@ void PrivilegeDb::UpdateAppPrivileges(const std::string &appId, uid_t uid, const std::vector &privileges) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand(Queries.at(QueryType::EAddAppPrivileges)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EAddAppPrivileges)); + + command->Reset(); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -249,9 +255,10 @@ void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege, std::vector &groups) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::EGetPrivilegeGroups)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EGetPrivilegeGroups)); + + command->Reset(); command->BindString(1, privilege.c_str()); while (command->Step()) { @@ -265,9 +272,10 @@ void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege, void PrivilegeDb::GetUserApps(uid_t uid, std::vector &apps) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr command = - mSqlConnection->PrepareDataCommand( - Queries.at(QueryType::EGetUserApps)); + DB::SqlConnection::DataCommandAutoPtr &command = + m_commands.at(static_cast(QueryType::EGetUserApps)); + + command->Reset(); command->BindInteger(1, static_cast(uid)); apps.clear(); while (command->Step()) { diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h index 373ad7f..510bacb 100644 --- a/src/dpl/db/include/dpl/db/sql_connection.h +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -364,7 +364,7 @@ class SqlConnection }; // Move on copy semantics - typedef std::auto_ptr DataCommandAutoPtr; + typedef std::unique_ptr DataCommandAutoPtr; // Open flags class Flag -- 2.7.4 From c4cde288b8198cbc7932bd38e0fa5b219f253c99 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Wed, 3 Dec 2014 12:18:04 +0100 Subject: [PATCH 09/16] Fix: disallow installing apps with the same id in different packages Change-Id: I04fca4edcd265e2853a9ce146e6dcc95d1f92dc9 Signed-off-by: Jan Cybulski --- src/client/client-security-manager.cpp | 2 ++ src/common/service_impl.cpp | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 1e03d36..34f4576 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -200,6 +200,8 @@ int security_manager_app_install(const app_inst_req *p_req) return SECURITY_MANAGER_SUCCESS; case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED: return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED; + case SECURITY_MANAGER_API_ERROR_INPUT_PARAM: + return SECURITY_MANAGER_ERROR_INPUT_PARAM; default: return SECURITY_MANAGER_ERROR_UNKNOWN; } diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index fe7982d..718868d 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -168,6 +168,14 @@ int appInstall(const app_inst_req &req, uid_t uid) << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); PrivilegeDb::getInstance().BeginTransaction(); + + std::string pkg; + bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg); + if (ret == true && pkg != req.pkgId) { + LogError("Application already installed with different package id"); + PrivilegeDb::getInstance().RollbackTransaction(); + return SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + } PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges); PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew); PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges); -- 2.7.4 From 5cb0da25db68f49143d576c133c2af1791661418 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Mon, 8 Dec 2014 15:30:07 +0100 Subject: [PATCH 10/16] Move database schema into a more convenient location Change-Id: I7444211fd43be873d62c423ccd32fac65e40773e Signed-off-by: Rafal Krypa --- CMakeLists.txt | 1 + db/CMakeLists.txt | 12 ++++++++++++ {src/server/db => db}/db.sql | 0 src/CMakeLists.txt | 3 +-- src/server/CMakeLists.txt | 10 ---------- 5 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 db/CMakeLists.txt rename {src/server/db => db}/db.sql (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 50d2589..1c5b171 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,3 +61,4 @@ ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG") ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(pc) ADD_SUBDIRECTORY(systemd) +ADD_SUBDIRECTORY(db) diff --git a/db/CMakeLists.txt b/db/CMakeLists.txt new file mode 100644 index 0000000..9e8ffcc --- /dev/null +++ b/db/CMakeLists.txt @@ -0,0 +1,12 @@ +SET(TARGET_DB ".security-manager.db") + +ADD_CUSTOM_COMMAND( + OUTPUT ${TARGET_DB} ${TARGET_DB}-journal + COMMAND sqlite3 ${TARGET_DB} Date: Mon, 8 Dec 2014 15:39:54 +0100 Subject: [PATCH 11/16] Server code no longer needs to include cynara and privilege-db headers Dependant code has been recently moved to common library. Change-Id: I5ae4a6a3ed43e00f5cf0e301ee33107844d36664 Signed-off-by: Rafal Krypa --- src/server/CMakeLists.txt | 2 -- src/server/service/include/service.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 72b151f..e006592 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,7 +1,6 @@ PKG_CHECK_MODULES(SERVER_DEP REQUIRED libsystemd-daemon - cynara-client ) FIND_PACKAGE(Boost REQUIRED) @@ -20,7 +19,6 @@ INCLUDE_DIRECTORIES( ${SERVER_PATH}/service/include ${DPL_PATH}/core/include ${DPL_PATH}/log/include - ${DPL_PATH}/db/include ) SET(SERVER_SOURCES diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 88b4870..1ceb7f8 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -29,8 +29,6 @@ #include #include #include -#include -#include namespace SecurityManager { -- 2.7.4 From 1db911c069897c53354ae8dd0c56b9797d627ce3 Mon Sep 17 00:00:00 2001 From: Bartlomiej Grzelewski Date: Wed, 9 Jul 2014 14:59:56 +0200 Subject: [PATCH 12/16] Fix minor errors in code. * m_maxDesc was used without initialization. * client-common module passed wrong value to poll if connect returns EINPROGRESS (was POLLIN, should be POLLOUT) Change backported from security-server repository. Change-Id: I4df6d67ff2214bd0ad857744a2c82bff5e7be299 Signed-off-by: Rafal Krypa --- src/client/client-common.cpp | 2 +- src/server/main/socket-manager.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/client/client-common.cpp b/src/client/client-common.cpp index 97176e5..783da66 100644 --- a/src/client/client-common.cpp +++ b/src/client/client-common.cpp @@ -120,7 +120,7 @@ public: int retval = TEMP_FAILURE_RETRY(connect(m_sock, (struct sockaddr*)&clientAddr, SUN_LEN(&clientAddr))); if ((retval == -1) && (errno == EINPROGRESS)) { - if (0 >= waitForSocket(m_sock, POLLIN, POLL_TIMEOUT)) { + if (0 >= waitForSocket(m_sock, POLLOUT, POLL_TIMEOUT)) { LogError("Error in waitForSocket."); return SECURITY_MANAGER_API_ERROR_SOCKET; } diff --git a/src/server/main/socket-manager.cpp b/src/server/main/socket-manager.cpp index cdbb191..7341c7f 100644 --- a/src/server/main/socket-manager.cpp +++ b/src/server/main/socket-manager.cpp @@ -136,7 +136,8 @@ SocketManager::CreateDefaultReadSocketDescription(int sock, bool timeout) } SocketManager::SocketManager() - : m_counter(0) + : m_maxDesc(0) + , m_counter(0) { FD_ZERO(&m_readSet); FD_ZERO(&m_writeSet); -- 2.7.4 From 616d70b470bb6c12c37eda8841cbba02535422d5 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Tue, 9 Dec 2014 13:29:08 +0100 Subject: [PATCH 13/16] PrivilegeDb: introduce convenient private method for fetching prepared query Create an internal method for repeating code pattern fetching the prepared query from internal data structure and resetting it before use. Change-Id: I346e5a0790d869632181737b52d6d5ba78da79c3 Signed-off-by: Rafal Krypa --- src/common/include/privilege_db.h | 9 +++++++ src/common/privilege_db.cpp | 52 ++++++++++++--------------------------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/common/include/privilege_db.h b/src/common/include/privilege_db.h index 1df7723..5135d93 100644 --- a/src/common/include/privilege_db.h +++ b/src/common/include/privilege_db.h @@ -96,6 +96,15 @@ private: void initDataCommands(); /** + * Return prepared query for given query type. + * The query will be reset before returning. + * + * @param queryType query identifier + * @return reference to prepared, reset query + */ + DB::SqlConnection::DataCommandAutoPtr & getQuery(QueryType queryType); + + /** * Check if pkgId is already registered in database * * @param pkgId - package identifier diff --git a/src/common/privilege_db.cpp b/src/common/privilege_db.cpp index cca5aaa..4d87cdd 100644 --- a/src/common/privilege_db.cpp +++ b/src/common/privilege_db.cpp @@ -76,6 +76,13 @@ void PrivilegeDb::initDataCommands() } } +DB::SqlConnection::DataCommandAutoPtr & PrivilegeDb::getQuery(QueryType queryType) +{ + auto &command = m_commands.at(static_cast(queryType)); + command->Reset(); + return command; +} + PrivilegeDb::~PrivilegeDb() { delete mSqlConnection; @@ -111,10 +118,7 @@ void PrivilegeDb::RollbackTransaction(void) bool PrivilegeDb::PkgIdExists(const std::string &pkgId) { return try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EPkgIdExists)); - - command->Reset(); + auto &command = getQuery(QueryType::EPkgIdExists); command->BindString(1, pkgId.c_str()); return command->Step(); }); @@ -123,10 +127,7 @@ bool PrivilegeDb::PkgIdExists(const std::string &pkgId) bool PrivilegeDb::GetAppPkgId(const std::string &appId, std::string &pkgId) { return try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EGetPkgId)); - - command->Reset(); + auto &command = getQuery(QueryType::EGetPkgId); command->BindString(1, appId.c_str()); if (!command->Step()) { @@ -147,10 +148,7 @@ void PrivilegeDb::AddApplication(const std::string &appId, pkgIdIsNew = !(this->PkgIdExists(pkgId)); try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EAddApplication)); - - command->Reset(); + auto &command = getQuery(QueryType::EAddApplication); command->BindString(1, appId.c_str()); command->BindString(2, pkgId.c_str()); command->BindInteger(3, static_cast(uid)); @@ -174,10 +172,7 @@ void PrivilegeDb::RemoveApplication(const std::string &appId, uid_t uid, return; } - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::ERemoveApplication)); - - command->Reset(); + auto &command = getQuery(QueryType::ERemoveApplication); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -196,10 +191,7 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId, uid_t uid, std::vector ¤tPrivileges) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EGetPkgPrivileges)); - - command->Reset(); + auto &command = getQuery(QueryType::EGetPkgPrivileges); command->BindString(1, pkgId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -214,10 +206,7 @@ void PrivilegeDb::GetPkgPrivileges(const std::string &pkgId, uid_t uid, void PrivilegeDb::RemoveAppPrivileges(const std::string &appId, uid_t uid) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::ERemoveAppPrivileges)); - - command->Reset(); + auto &command = getQuery(QueryType::ERemoveAppPrivileges); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); if (command->Step()) { @@ -233,10 +222,7 @@ void PrivilegeDb::UpdateAppPrivileges(const std::string &appId, uid_t uid, const std::vector &privileges) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EAddAppPrivileges)); - - command->Reset(); + auto &command = getQuery(QueryType::EAddAppPrivileges); command->BindString(1, appId.c_str()); command->BindInteger(2, static_cast(uid)); @@ -255,10 +241,7 @@ void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege, std::vector &groups) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EGetPrivilegeGroups)); - - command->Reset(); + auto &command = getQuery(QueryType::EGetPrivilegeGroups); command->BindString(1, privilege.c_str()); while (command->Step()) { @@ -272,10 +255,7 @@ void PrivilegeDb::GetPrivilegeGroups(const std::string &privilege, void PrivilegeDb::GetUserApps(uid_t uid, std::vector &apps) { try_catch([&] { - DB::SqlConnection::DataCommandAutoPtr &command = - m_commands.at(static_cast(QueryType::EGetUserApps)); - - command->Reset(); + auto &command = getQuery(QueryType::EGetUserApps); command->BindInteger(1, static_cast(uid)); apps.clear(); while (command->Step()) { -- 2.7.4 From f60b99ea686d982c667254e43db62ff5df822e45 Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Wed, 10 Dec 2014 07:58:03 +0100 Subject: [PATCH 14/16] Add API for user management Change-Id: I429dfa82b7cb669713b357ebe50d0b599ad8ebed Signed-off-by: Jan Cybulski --- src/client/client-security-manager.cpp | 57 ++++++++++++++++++++++ src/common/include/protocols.h | 5 ++ src/include/security-manager.h | 86 ++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 34f4576..8625649 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -517,3 +517,60 @@ int security_manager_prepare_app(const char *app_id) ret = security_manager_drop_process_privileges(); return ret; } + +SECURITY_MANAGER_API +int security_manager_user_req_new(user_req **pp_req) +{ + if (!pp_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + try { + *pp_req = new user_req; + } catch (std::bad_alloc& ex) { + return SECURITY_MANAGER_ERROR_MEMORY; + } + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +void security_manager_user_req_free(user_req *p_req) +{ + delete p_req; +} + +SECURITY_MANAGER_API +int security_manager_user_req_set_uid(user_req *p_req, uid_t uid) +{ + if (!p_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + + p_req->uid = uid; + + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_user_req_set_user_type(user_req *p_req, security_manager_user_type utype) +{ + if (!p_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + + p_req->utype = static_cast(utype); + + return SECURITY_MANAGER_SUCCESS; +} + +SECURITY_MANAGER_API +int security_manager_user_add(const user_req *p_req) +{ + //TODO + (void) p_req; + return SECURITY_MANAGER_ERROR_UNKNOWN; +} + +SECURITY_MANAGER_API +int security_manager_user_delete(const user_req *p_req) +{ + //TODO + (void) p_req; + return SECURITY_MANAGER_ERROR_UNKNOWN; +} diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index d9c092f..029ba95 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -109,6 +109,11 @@ struct app_inst_req { uid_t uid; }; +struct user_req { + uid_t uid; + int utype; +}; + namespace SecurityManager { extern char const * const SERVICE_SOCKET; diff --git a/src/include/security-manager.h b/src/include/security-manager.h index 36028c2..5e0f15b 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -55,11 +55,32 @@ enum app_install_path_type { SECURITY_MANAGER_ENUM_END }; +/** + * This enum has values equivalent to gumd user type. + * The gum-utils help states that + * "usertype can be system(1), admin(2), guest(3), normal(4)." + */ +enum security_manager_user_type { + SM_USER_TYPE_NONE = 0,/*<-this should not be used, if it is used, there will be an error returned by SM*/ + SM_USER_TYPE_SYSTEM = 1, + SM_USER_TYPE_ADMIN = 2, + SM_USER_TYPE_GUEST = 3, + SM_USER_TYPE_NORMAL = 4, + SM_USER_TYPE_ANY = 5,/*<-this value may be used only for setting policies and not during user adding*/ + SM_USER_TYPE_END +}; +typedef enum security_manager_user_type security_manager_user_type; + /*! \brief data structure responsible for handling informations * required to install / uninstall application */ struct app_inst_req; typedef struct app_inst_req app_inst_req; +/*! \brief data structure responsible for handling informations + * required to manage users */ +struct user_req; +typedef struct user_req user_req; + /** * This function translates lib_retcode error codes to strings describing * errors. @@ -219,6 +240,71 @@ int security_manager_drop_process_privileges(void); */ int security_manager_prepare_app(const char *app_id); +/* + * This function is responsible for initialization of user_req data structure. + * It uses dynamic allocation inside and user responsibility is to call + * security_manager_user_req_free() for freeing allocated resources. + * + * @param[in] Address of pointer for handle user_req structure + * @return API return code or error code + */ +int security_manager_user_req_new(user_req **pp_req); + +/* + * This function is used to free resources allocated by + * security_manager_user_req_new() + * + * @param[in] Pointer handling allocated user_req structure + */ +void security_manager_user_req_free(user_req *p_req); + +/* + * This function is used to set up user identifier in user_req structure. + * + * @param p_req Structure containing user data filled during this function call + * @param uid User identifier to be set + * @return API return code or error code + */ +int security_manager_user_req_set_uid(user_req *p_req, uid_t uid); + +/* + * This function is used to set up user type in user_req structure. + * + * @param p_req Structure containing user data filled during this function call + * @param utype User type to be set + * @return API return code or error code + */ +int security_manager_user_req_set_user_type(user_req *p_req, security_manager_user_type utype); + +/* + * This function should be called to inform security-manager about adding new user. + * This function succeeds only when is called by privileged user. + * Otherwise it just returns SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED and does nothing. + * + * It adds all required privileges to a newly created user. + * User data are passed through pointer 'p_req'. + * @param p_req Structure containing user data filled before calling this + * uid and user type needs to be filled in p_req structure, + * otherwise SECURITY_MANAGER_ERROR_INPUT_PARAM will be returned. + * @return API return code or error code. + */ +int security_manager_user_add(const user_req *p_req); + +/* + * This function should be called to inform security-manager about removing a user. + * This function succeeds only when is called by privileged user. + * Otherwise it just returns SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED and does nothing. + * + * It removes all privileges granted to a user that has been granted previously by + * security_manager_user_add. + * + * @param p_req Structure containing user data filled before calling this. + * uid of user needs to be filled in p_req structure, + * otherwise SECURITY_MANAGER_ERROR_INPUT_PARAM will be returned. + * @return API return code or error code + */ +int security_manager_user_delete(const user_req *p_req); + #ifdef __cplusplus } -- 2.7.4 From 7eca0f84d70ccd7a9939f9afad7220fad0d130dc Mon Sep 17 00:00:00 2001 From: Jan Cybulski Date: Thu, 27 Nov 2014 08:28:53 +0100 Subject: [PATCH 15/16] Implementation of API for user management Change-Id: Ib2cb08e1c466bc93775f8efe32dccd118ef095ad Signed-off-by: Jan Cybulski --- src/client/client-security-manager.cpp | 66 ++++++++++++++++++++++++++++++---- src/common/include/protocols.h | 2 ++ src/common/include/service_impl.h | 21 +++++++++++ src/common/service_impl.cpp | 50 ++++++++++++++++++++++++++ src/server/service/include/service.h | 5 +++ src/server/service/service.cpp | 30 ++++++++++++++++ 6 files changed, 168 insertions(+), 6 deletions(-) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 8625649..f9e3484 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -562,15 +562,69 @@ int security_manager_user_req_set_user_type(user_req *p_req, security_manager_us SECURITY_MANAGER_API int security_manager_user_add(const user_req *p_req) { - //TODO - (void) p_req; - return SECURITY_MANAGER_ERROR_UNKNOWN; + using namespace SecurityManager; + MessageBuffer send, recv; + if (!p_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + return try_catch([&] { + + //put data into buffer + Serialization::Serialize(send, static_cast(SecurityModuleCall::USER_ADD)); + + Serialization::Serialize(send, p_req->uid); + Serialization::Serialize(send, p_req->utype); + + //send buffer 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; + } + }); } SECURITY_MANAGER_API int security_manager_user_delete(const user_req *p_req) { - //TODO - (void) p_req; - return SECURITY_MANAGER_ERROR_UNKNOWN; + using namespace SecurityManager; + MessageBuffer send, recv; + if (!p_req) + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + return try_catch([&] { + + //put data into buffer + Serialization::Serialize(send, static_cast(SecurityModuleCall::USER_DELETE)); + + Serialization::Serialize(send, p_req->uid); + + + //send buffer 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; + } + }); } diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 029ba95..11b93a5 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -124,6 +124,8 @@ enum class SecurityModuleCall APP_UNINSTALL, APP_GET_PKGID, APP_GET_GROUPS, + USER_ADD, + USER_DELETE, }; } // namespace SecurityManager diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index ba6a580..3df8975 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -81,6 +81,27 @@ int getPkgId(const std::string &appId, std::string &pkgId); */ int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids); +/** + * Process user adding request. + * + * @param[in] uidAdded uid of newly created user + * @param[in] userType type of newly created user + * @param[in] uid uid of requesting user + * + * @return API return code, as defined in protocols.h + */ +int userAdd(uid_t uidAdded, int userType, uid_t uid); + +/** + * Process user deletion request. + * + * @param[in] uidDeleted uid of removed user + * @param[in] uid uid of requesting user + * + * @return API return code, as defined in protocols.h + */ +int userDelete(uid_t uidDeleted, uid_t uid); + } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 718868d..6660561 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -377,5 +377,55 @@ int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_ return SECURITY_MANAGER_API_SUCCESS; } +int userAdd(uid_t uidAdded, int userType, uid_t uid) +{ + if (uid != 0) + return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED; + + switch (userType) { + case SM_USER_TYPE_SYSTEM: + case SM_USER_TYPE_ADMIN: + case SM_USER_TYPE_GUEST: + case SM_USER_TYPE_NORMAL: + break; + default: + return SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + } + + //TODO add policy information to cynara regarding user default privileges based on user_type + (void) uidAdded; + (void) userType; + + return SECURITY_MANAGER_API_SUCCESS; +} + +int userDelete(uid_t uidDeleted, uid_t uid) +{ + int ret = SECURITY_MANAGER_API_SUCCESS; + if (uid != 0) + return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED; + + //TODO remove policy information from cynara + + /*Uninstall all user apps*/ + std::vector userApps; + try { + PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps); + } catch (const PrivilegeDb::Exception::Base &e) { + LogError("Error while getting user apps from database: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + + for (auto &app: userApps) { + if (appUninstall(app, uidDeleted) != SECURITY_MANAGER_API_SUCCESS) { + /*if uninstallation of this app fails, just go on trying to uninstall another ones. + we do not have anything special to do about that matter - user will be deleted anyway.*/ + ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + + return ret; +} + } /* namespace ServiceImpl */ } /* namespace SecurityManager */ diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 1ceb7f8..19385f7 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -105,6 +105,11 @@ private: * @param pid Process id in which application will be launched */ void processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid); + + void processUserAdd(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); + + void processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid); + }; } // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 5b83421..046dd20 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -141,6 +141,12 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer, case SecurityModuleCall::APP_GET_GROUPS: processGetAppGroups(buffer, send, uid, pid); break; + case SecurityModuleCall::USER_ADD: + processUserAdd(buffer, send, uid); + break; + case SecurityModuleCall::USER_DELETE: + processUserDelete(buffer, send, uid); + break; default: LogError("Invalid call: " << call_type_int); Throw(ServiceException::InvalidAction); @@ -222,5 +228,29 @@ void Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, ui } } +void Service::processUserAdd(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) +{ + int ret; + uid_t uidAdded; + int userType; + + Deserialization::Deserialize(buffer, uidAdded); + Deserialization::Deserialize(buffer, userType); + + ret = ServiceImpl::userAdd(uidAdded, userType, uid); + Serialization::Serialize(send, ret); +} + +void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) +{ + int ret; + uid_t uidRemoved; + + Deserialization::Deserialize(buffer, uidRemoved); + + ret = ServiceImpl::userDelete(uidRemoved, uid); + Serialization::Serialize(send, ret); +} + } // namespace SecurityManager -- 2.7.4 From 87b81b24f51f6618d201bd30b221fbbfec890709 Mon Sep 17 00:00:00 2001 From: Krzysztof Sasiak Date: Thu, 27 Nov 2014 11:02:44 +0100 Subject: [PATCH 16/16] Add security-manager policy for user types Change-Id: I1c5ea026fe3b69ec0d2ba1338ded1033ad5db6b2 --- packaging/security-manager.spec | 14 ++++++++++ policy/usertype-admin.profile | 60 +++++++++++++++++++++++++++++++++++++++++ policy/usertype-guest.profile | 60 +++++++++++++++++++++++++++++++++++++++++ policy/usertype-normal.profile | 60 +++++++++++++++++++++++++++++++++++++++++ policy/usertype-system.profile | 60 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 policy/usertype-admin.profile create mode 100644 policy/usertype-guest.profile create mode 100644 policy/usertype-normal.profile create mode 100644 policy/usertype-system.profile diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index cd68faa..817bc3d 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -44,6 +44,14 @@ Requires: libsecurity-manager-client = %{version}-%{release} %description -n libsecurity-manager-client-devel Development files needed for using the security manager client +%package -n security-manager-policy +Summary: Security manager policy +Group: Security/Development +Requires: security-manager = %{version}-%{release} + +%description -n security-manager-policy +Set of security rules that constitute security policy in the system + %prep %setup -q cp %{SOURCE1} . @@ -73,6 +81,8 @@ cp LICENSE %{buildroot}/usr/share/license/%{name} cp LICENSE %{buildroot}/usr/share/license/libsecurity-manager-client mkdir -p %{buildroot}/%{TZ_SYS_SMACK} cp app-rules-template.smack %{buildroot}/%{TZ_SYS_SMACK} +mkdir -p %{buildroot}/usr/share/security-manager +cp -rf policy %{buildroot}/usr/share/security-manager %make_install mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants @@ -144,3 +154,7 @@ fi %{_libdir}/libsecurity-manager-commons.so %{_includedir}/security-manager/security-manager.h %{_libdir}/pkgconfig/security-manager.pc + +%files -n security-manager-policy +%manifest %{name}.manifest +/usr/share/security-manager/policy diff --git a/policy/usertype-admin.profile b/policy/usertype-admin.profile new file mode 100644 index 0000000..40c43e1 --- /dev/null +++ b/policy/usertype-admin.profile @@ -0,0 +1,60 @@ +'Admin usertype permissions +'app permission +* http://tizen.org/privilege/account.read +* http://tizen.org/privilege/account.write +* http://tizen.org/privilege/alarm.get +* http://tizen.org/privilege/alarm.set +* http://tizen.org/privilege/appmanager.kill +* http://tizen.org/privilege/appmanager.launch +* http://tizen.org/privilege/bluetooth +* http://tizen.org/privilege/bluetooth.admin +* http://tizen.org/privilege/bookmark.admin +* http://tizen.org/privilege/calendar.read +* http://tizen.org/privilege/calendar.write +* http://tizen.org/privilege/call +* http://tizen.org/privilege/callhistory.read +* http://tizen.org/privilege/callhistory.write +* http://tizen.org/privilege/camera +* http://tizen.org/privilege/contact.read +* http://tizen.org/privilege/contact.write +* http://tizen.org/privilege/content.write +* http://tizen.org/privilege/datasharing +* http://tizen.org/privilege/display +* http://tizen.org/privilege/download +* http://tizen.org/privilege/email +* http://tizen.org/privilege/email.admin +* http://tizen.org/privilege/externalstorage +* http://tizen.org/privilege/externalstorage.appdata +* http://tizen.org/privilege/haptic +* http://tizen.org/privilege/internet +* http://tizen.org/privilege/keymanager +* http://tizen.org/privilege/keymanager.admin +* http://tizen.org/privilege/led +* http://tizen.org/privilege/location +* http://tizen.org/privilege/location.enable +* http://tizen.org/privilege/mediastorage +* http://tizen.org/privilege/message.read +* http://tizen.org/privilege/message.write +* http://tizen.org/privilege/network.get +* http://tizen.org/privilege/network.profile +* http://tizen.org/privilege/network.set +* http://tizen.org/privilege/nfc +* http://tizen.org/privilege/nfc.admin +* http://tizen.org/privilege/nfc.cardemulation +* http://tizen.org/privilege/notification +* http://tizen.org/privilege/packagemanager.admin +* http://tizen.org/privilege/packagemanager.info +* http://tizen.org/privilege/power +* http://tizen.org/privilege/push +* http://tizen.org/privilege/recorder +* http://tizen.org/privilege/screenshot +* http://tizen.org/privilege/shortcut +* http://tizen.org/privilege/systemsettings +* http://tizen.org/privilege/systemsettings.admin +* http://tizen.org/privilege/telephony +* http://tizen.org/privilege/telephony.admin +* http://tizen.org/privilege/tethering.admin +* http://tizen.org/privilege/volume.set +* http://tizen.org/privilege/web-history.admin +* http://tizen.org/privilege/wifidirect +* http://tizen.org/privilege/window.priority.set diff --git a/policy/usertype-guest.profile b/policy/usertype-guest.profile new file mode 100644 index 0000000..3d40722 --- /dev/null +++ b/policy/usertype-guest.profile @@ -0,0 +1,60 @@ +'Guest usertype permissions +'app permission +* http://tizen.org/privilege/account.read +* http://tizen.org/privilege/account.write +* http://tizen.org/privilege/alarm.get +* http://tizen.org/privilege/alarm.set +* http://tizen.org/privilege/appmanager.kill +* http://tizen.org/privilege/appmanager.launch +* http://tizen.org/privilege/bluetooth +* http://tizen.org/privilege/bluetooth.admin +* http://tizen.org/privilege/bookmark.admin +* http://tizen.org/privilege/calendar.read +* http://tizen.org/privilege/calendar.write +* http://tizen.org/privilege/call +* http://tizen.org/privilege/callhistory.read +* http://tizen.org/privilege/callhistory.write +* http://tizen.org/privilege/camera +* http://tizen.org/privilege/contact.read +* http://tizen.org/privilege/contact.write +* http://tizen.org/privilege/content.write +* http://tizen.org/privilege/datasharing +* http://tizen.org/privilege/display +* http://tizen.org/privilege/download +* http://tizen.org/privilege/email +* http://tizen.org/privilege/email.admin +* http://tizen.org/privilege/externalstorage +* http://tizen.org/privilege/externalstorage.appdata +* http://tizen.org/privilege/haptic +* http://tizen.org/privilege/internet +* http://tizen.org/privilege/keymanager +* http://tizen.org/privilege/keymanager.admin +* http://tizen.org/privilege/led +* http://tizen.org/privilege/location +* http://tizen.org/privilege/location.enable +* http://tizen.org/privilege/mediastorage +* http://tizen.org/privilege/message.read +* http://tizen.org/privilege/message.write +* http://tizen.org/privilege/network.get +* http://tizen.org/privilege/network.profile +* http://tizen.org/privilege/network.set +* http://tizen.org/privilege/nfc +* http://tizen.org/privilege/nfc.admin +* http://tizen.org/privilege/nfc.cardemulation +* http://tizen.org/privilege/notification +* http://tizen.org/privilege/packagemanager.admin +* http://tizen.org/privilege/packagemanager.info +* http://tizen.org/privilege/power +* http://tizen.org/privilege/push +* http://tizen.org/privilege/recorder +* http://tizen.org/privilege/screenshot +* http://tizen.org/privilege/shortcut +* http://tizen.org/privilege/systemsettings +* http://tizen.org/privilege/systemsettings.admin +* http://tizen.org/privilege/telephony +* http://tizen.org/privilege/telephony.admin +* http://tizen.org/privilege/tethering.admin +* http://tizen.org/privilege/volume.set +* http://tizen.org/privilege/web-history.admin +* http://tizen.org/privilege/wifidirect +* http://tizen.org/privilege/window.priority.set diff --git a/policy/usertype-normal.profile b/policy/usertype-normal.profile new file mode 100644 index 0000000..365b3f2 --- /dev/null +++ b/policy/usertype-normal.profile @@ -0,0 +1,60 @@ +'Normal usertype permissions +'app permission +* http://tizen.org/privilege/account.read +* http://tizen.org/privilege/account.write +* http://tizen.org/privilege/alarm.get +* http://tizen.org/privilege/alarm.set +* http://tizen.org/privilege/appmanager.kill +* http://tizen.org/privilege/appmanager.launch +* http://tizen.org/privilege/bluetooth +* http://tizen.org/privilege/bluetooth.admin +* http://tizen.org/privilege/bookmark.admin +* http://tizen.org/privilege/calendar.read +* http://tizen.org/privilege/calendar.write +* http://tizen.org/privilege/call +* http://tizen.org/privilege/callhistory.read +* http://tizen.org/privilege/callhistory.write +* http://tizen.org/privilege/camera +* http://tizen.org/privilege/contact.read +* http://tizen.org/privilege/contact.write +* http://tizen.org/privilege/content.write +* http://tizen.org/privilege/datasharing +* http://tizen.org/privilege/display +* http://tizen.org/privilege/download +* http://tizen.org/privilege/email +* http://tizen.org/privilege/email.admin +* http://tizen.org/privilege/externalstorage +* http://tizen.org/privilege/externalstorage.appdata +* http://tizen.org/privilege/haptic +* http://tizen.org/privilege/internet +* http://tizen.org/privilege/keymanager +* http://tizen.org/privilege/keymanager.admin +* http://tizen.org/privilege/led +* http://tizen.org/privilege/location +* http://tizen.org/privilege/location.enable +* http://tizen.org/privilege/mediastorage +* http://tizen.org/privilege/message.read +* http://tizen.org/privilege/message.write +* http://tizen.org/privilege/network.get +* http://tizen.org/privilege/network.profile +* http://tizen.org/privilege/network.set +* http://tizen.org/privilege/nfc +* http://tizen.org/privilege/nfc.admin +* http://tizen.org/privilege/nfc.cardemulation +* http://tizen.org/privilege/notification +* http://tizen.org/privilege/packagemanager.admin +* http://tizen.org/privilege/packagemanager.info +* http://tizen.org/privilege/power +* http://tizen.org/privilege/push +* http://tizen.org/privilege/recorder +* http://tizen.org/privilege/screenshot +* http://tizen.org/privilege/shortcut +* http://tizen.org/privilege/systemsettings +* http://tizen.org/privilege/systemsettings.admin +* http://tizen.org/privilege/telephony +* http://tizen.org/privilege/telephony.admin +* http://tizen.org/privilege/tethering.admin +* http://tizen.org/privilege/volume.set +* http://tizen.org/privilege/web-history.admin +* http://tizen.org/privilege/wifidirect +* http://tizen.org/privilege/window.priority.set diff --git a/policy/usertype-system.profile b/policy/usertype-system.profile new file mode 100644 index 0000000..2cd6360 --- /dev/null +++ b/policy/usertype-system.profile @@ -0,0 +1,60 @@ +'System usertype permissions +'app permission +* http://tizen.org/privilege/account.read +* http://tizen.org/privilege/account.write +* http://tizen.org/privilege/alarm.get +* http://tizen.org/privilege/alarm.set +* http://tizen.org/privilege/appmanager.kill +* http://tizen.org/privilege/appmanager.launch +* http://tizen.org/privilege/bluetooth +* http://tizen.org/privilege/bluetooth.admin +* http://tizen.org/privilege/bookmark.admin +* http://tizen.org/privilege/calendar.read +* http://tizen.org/privilege/calendar.write +* http://tizen.org/privilege/call +* http://tizen.org/privilege/callhistory.read +* http://tizen.org/privilege/callhistory.write +* http://tizen.org/privilege/camera +* http://tizen.org/privilege/contact.read +* http://tizen.org/privilege/contact.write +* http://tizen.org/privilege/content.write +* http://tizen.org/privilege/datasharing +* http://tizen.org/privilege/display +* http://tizen.org/privilege/download +* http://tizen.org/privilege/email +* http://tizen.org/privilege/email.admin +* http://tizen.org/privilege/externalstorage +* http://tizen.org/privilege/externalstorage.appdata +* http://tizen.org/privilege/haptic +* http://tizen.org/privilege/internet +* http://tizen.org/privilege/keymanager +* http://tizen.org/privilege/keymanager.admin +* http://tizen.org/privilege/led +* http://tizen.org/privilege/location +* http://tizen.org/privilege/location.enable +* http://tizen.org/privilege/mediastorage +* http://tizen.org/privilege/message.read +* http://tizen.org/privilege/message.write +* http://tizen.org/privilege/network.get +* http://tizen.org/privilege/network.profile +* http://tizen.org/privilege/network.set +* http://tizen.org/privilege/nfc +* http://tizen.org/privilege/nfc.admin +* http://tizen.org/privilege/nfc.cardemulation +* http://tizen.org/privilege/notification +* http://tizen.org/privilege/packagemanager.admin +* http://tizen.org/privilege/packagemanager.info +* http://tizen.org/privilege/power +* http://tizen.org/privilege/push +* http://tizen.org/privilege/recorder +* http://tizen.org/privilege/screenshot +* http://tizen.org/privilege/shortcut +* http://tizen.org/privilege/systemsettings +* http://tizen.org/privilege/systemsettings.admin +* http://tizen.org/privilege/telephony +* http://tizen.org/privilege/telephony.admin +* http://tizen.org/privilege/tethering.admin +* http://tizen.org/privilege/volume.set +* http://tizen.org/privilege/web-history.admin +* http://tizen.org/privilege/wifidirect +* http://tizen.org/privilege/window.priority.set -- 2.7.4