From 275b5c0b5c495abd84da7779bef9354755446449 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Thu, 19 Mar 2015 17:53:03 +0100 Subject: [PATCH 01/16] Fix advisory locking in client library Enhance off-line mode detection based on lock: - don't use exceptions for non-exceptional code paths - only attempt off-line mode if caller is root Also fix misleading logs informing about lock failures (that doesn't lead to actual security-mnanager failures) caused by lock attempt on a lock file without proper permissions. Change-Id: Ie7fca37154a1993cd46c59a0204837904593e5db Signed-off-by: Rafal Krypa --- src/client/client-offline.cpp | 9 ++++++++- src/common/file-lock.cpp | 41 ++++++++++++++++------------------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/client/client-offline.cpp b/src/client/client-offline.cpp index f926d77..e442c2f 100644 --- a/src/client/client-offline.cpp +++ b/src/client/client-offline.cpp @@ -35,6 +35,12 @@ ClientOffline::ClientOffline() { offlineMode = false; serviceLock = nullptr; + + if (geteuid()) { + LogInfo("UID != 0, attempting only on-line mode."); + return; + } + try { serviceLock = new SecurityManager::FileLocker(SecurityManager::SERVICE_LOCK_FILE, false); if (serviceLock->Locked()) { @@ -53,7 +59,8 @@ ClientOffline::ClientOffline() LogInfo("Service seems to be running now."); } } catch (...) { - /* Ignore exceptions, assume on-line */ + LogError("Cannot detect off-line mode by lock."); + offlineMode = false; } if (offlineMode) diff --git a/src/common/file-lock.cpp b/src/common/file-lock.cpp index 36b2ccb..6f3996c 100644 --- a/src/common/file-lock.cpp +++ b/src/common/file-lock.cpp @@ -41,18 +41,11 @@ FileLocker::FileLocker(const std::string &lockFile, bool blocking) ThrowMsg(FileLocker::Exception::LockFailed, "File name can not be empty."); } - try { - m_locked = false; - m_blocking = blocking; - m_lockFile = lockFile; - Lock(); - } catch (FileLocker::Exception::Base &e) { - LogError("Failed to lock " << lockFile << " file: " - << e.DumpToString()); - ThrowMsg(FileLocker::Exception::LockFailed, - "Failed to lock " << lockFile << " file: " - << e.DumpToString()); - } + + m_locked = false; + m_blocking = blocking; + m_lockFile = lockFile; + Lock(); } FileLocker::~FileLocker() @@ -69,9 +62,11 @@ void FileLocker::Lock() { if (m_locked) return; + try { - if (!std::ifstream(m_lockFile).good()) - std::ofstream(m_lockFile.c_str()); + std::ofstream tmpf(m_lockFile); + tmpf.close(); + m_flock = boost::interprocess::file_lock(m_lockFile.c_str()); if (m_blocking) { m_flock.lock(); @@ -79,19 +74,15 @@ void FileLocker::Lock() } else m_locked = m_flock.try_lock(); } catch (const std::exception &e) { - ThrowMsg(FileLocker::Exception::LockFailed, - "Error while locking a file."); + LogError("Error while locking a file: " << e.what()); + ThrowMsg(FileLocker::Exception::LockFailed, + "Error while locking a file: " << e.what()); } - if (m_locked) { + + if (m_locked) LogDebug("We have a lock on " << m_lockFile << " file."); - } else { - if (m_blocking) { - ThrowMsg(FileLocker::Exception::LockFailed, - "Unable to lock file."); - } else { - LogDebug("Impossible to lock a file now."); - } - } + else + LogDebug("Impossible to lock a file now."); } void FileLocker::Unlock() -- 2.7.4 From 6eb825a3876061b2e152d42974e117dcbedf7c70 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 20 Mar 2015 16:19:44 +0100 Subject: [PATCH 02/16] Release version 1.0.1 Change-Id: Ied8852ec3ed3e8dc3ea3457a99ee4a9822349f55 --- packaging/security-manager.changes | 4 ++++ packaging/security-manager.spec | 2 +- pc/security-manager.pc.in | 2 +- src/client/CMakeLists.txt | 2 +- src/common/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packaging/security-manager.changes b/packaging/security-manager.changes index ff5d6d3..1c02c3a 100644 --- a/packaging/security-manager.changes +++ b/packaging/security-manager.changes @@ -1,3 +1,7 @@ +* Fri Mar 20 2015 Rafal Krypa +- Version 1.0.1 +- Bug-fix release, no new features. + * Fri Mar 06 2015 Rafal Krypa - Version 1.0.0 - User management diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 92496b2..1ebced1 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -1,6 +1,6 @@ Name: security-manager Summary: Security manager and utilities -Version: 1.0.0 +Version: 1.0.1 Release: 1 Group: Security/Service License: Apache-2.0 diff --git a/pc/security-manager.pc.in b/pc/security-manager.pc.in index b008725..ec43046 100644 --- a/pc/security-manager.pc.in +++ b/pc/security-manager.pc.in @@ -5,7 +5,7 @@ includedir=${prefix}/include Name: security-manager Description: Security Manager Package -Version: 1.0.0 +Version: 1.0.1 Requires: Libs: -L${libdir} -lsecurity-manager-client Cflags: -I${includedir}/security-manager diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 6f7b033..66a33ab 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -5,7 +5,7 @@ PKG_CHECK_MODULES(CLIENT_DEP ) SET(CLIENT_VERSION_MAJOR 1) -SET(CLIENT_VERSION ${CLIENT_VERSION_MAJOR}.0.0) +SET(CLIENT_VERSION ${CLIENT_VERSION_MAJOR}.0.1) INCLUDE_DIRECTORIES(SYSTEM ${CLIENT_DEP_INCLUDE_DIRS} diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e1575e4..cbcea64 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,5 +1,5 @@ SET(COMMON_VERSION_MAJOR 1) -SET(COMMON_VERSION ${COMMON_VERSION_MAJOR}.0.0) +SET(COMMON_VERSION ${COMMON_VERSION_MAJOR}.0.1) PKG_CHECK_MODULES(COMMON_DEP REQUIRED -- 2.7.4 From 5462f5e2da37bef5519d63511f0dd08f155c1f0b Mon Sep 17 00:00:00 2001 From: Stephane Desneux Date: Wed, 25 Mar 2015 11:27:38 +0100 Subject: [PATCH 03/16] Raise socket inactivity timeout to 300s This is a quick workaround to installation problems on slow targets. Bug-Tizen: TC-2483 Change-Id: I6515438e7fdc02ba6c6de6efba32cfcaaa030f7f Signed-off-by: Stephane Desneux --- src/server/main/socket-manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/main/socket-manager.cpp b/src/server/main/socket-manager.cpp index d917a68..94c54c6 100644 --- a/src/server/main/socket-manager.cpp +++ b/src/server/main/socket-manager.cpp @@ -48,7 +48,7 @@ namespace { -const time_t SOCKET_TIMEOUT = 20; +const time_t SOCKET_TIMEOUT = 300; } // namespace anonymous -- 2.7.4 From beb6b6fcae57dc62f0c01831dd1510e8ad9dfecd Mon Sep 17 00:00:00 2001 From: Lukasz Wojciechowski Date: Wed, 25 Mar 2015 11:50:36 +0100 Subject: [PATCH 04/16] Don't call Cynara if there are no policies to set Change-Id: I3a25cbc0cdbf5ee4cb82890fbd40ea4e51b8a08d --- src/common/cynara.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 6d19977..29b06bc 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -249,6 +249,11 @@ CynaraAdmin &CynaraAdmin::getInstance() void CynaraAdmin::SetPolicies(const std::vector &policies) { + if (policies.empty()) { + LogDebug("no policies to set in Cynara."); + return; + } + std::vector pp_policies(policies.size() + 1); LogDebug("Sending " << policies.size() << " policies to Cynara"); -- 2.7.4 From 860305a595d681d650024ad07b3b0977e1fcb0a6 Mon Sep 17 00:00:00 2001 From: Jacek Bukarewicz Date: Wed, 25 Mar 2015 11:44:33 +0100 Subject: [PATCH 05/16] Release version 1.0.2 Change-Id: Ia46e9cf268fe0a7302066ee014e5d44c393fb587 --- packaging/security-manager.changes | 4 ++++ packaging/security-manager.spec | 2 +- pc/security-manager.pc.in | 2 +- src/client/CMakeLists.txt | 2 +- src/common/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packaging/security-manager.changes b/packaging/security-manager.changes index 1c02c3a..2bc5c15 100644 --- a/packaging/security-manager.changes +++ b/packaging/security-manager.changes @@ -1,3 +1,7 @@ +* Wed Mar 25 2015 Jacek Bukarewicz +- Version 1.0.2 +- Work around application installation problems on slow targets + * Fri Mar 20 2015 Rafal Krypa - Version 1.0.1 - Bug-fix release, no new features. diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 1ebced1..5269334 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -1,6 +1,6 @@ Name: security-manager Summary: Security manager and utilities -Version: 1.0.1 +Version: 1.0.2 Release: 1 Group: Security/Service License: Apache-2.0 diff --git a/pc/security-manager.pc.in b/pc/security-manager.pc.in index ec43046..c2916c5 100644 --- a/pc/security-manager.pc.in +++ b/pc/security-manager.pc.in @@ -5,7 +5,7 @@ includedir=${prefix}/include Name: security-manager Description: Security Manager Package -Version: 1.0.1 +Version: 1.0.2 Requires: Libs: -L${libdir} -lsecurity-manager-client Cflags: -I${includedir}/security-manager diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 66a33ab..5399a55 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -5,7 +5,7 @@ PKG_CHECK_MODULES(CLIENT_DEP ) SET(CLIENT_VERSION_MAJOR 1) -SET(CLIENT_VERSION ${CLIENT_VERSION_MAJOR}.0.1) +SET(CLIENT_VERSION ${CLIENT_VERSION_MAJOR}.0.2) INCLUDE_DIRECTORIES(SYSTEM ${CLIENT_DEP_INCLUDE_DIRS} diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index cbcea64..2da9c3e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -1,5 +1,5 @@ SET(COMMON_VERSION_MAJOR 1) -SET(COMMON_VERSION ${COMMON_VERSION_MAJOR}.0.1) +SET(COMMON_VERSION ${COMMON_VERSION_MAJOR}.0.2) PKG_CHECK_MODULES(COMMON_DEP REQUIRED -- 2.7.4 From d5559a8207f79896129d734911f385d2d08ac024 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 6 Feb 2015 18:25:11 +0100 Subject: [PATCH 06/16] Prepare security-manager for master-slave mode This commit prepares security-manager for work in master/slave mode. In order to properly install/uninstall applications inside containers, security-manager inside container (slave) must delegate calls related to SMACK to security-manager outside a container (master). Since entire master/slave mode is a huge change, it is divided into two commits - this is the first one. Logic for master service and changes in service to work as slave are left for second commit. With this change security-manager launched without additional arguments should work as it did. Change-Id: If05cdeb2d2c35c046bf4cb46d884a3689dab57ad --- packaging/security-manager.spec | 6 ++ src/common/include/protocols.h | 2 + src/common/include/service_impl.h | 11 +++ src/common/protocols.cpp | 4 + src/common/service_impl.cpp | 15 ++++ src/server/CMakeLists.txt | 4 +- src/server/main/server-main.cpp | 86 ++++++++++++++++++--- src/server/service/include/master-service.h | 61 +++++++++++++++ src/server/service/include/service.h | 4 +- src/server/service/master-service.cpp | 111 ++++++++++++++++++++++++++++ src/server/service/service.cpp | 26 +++++-- systemd/CMakeLists.txt | 6 ++ systemd/security-manager-master.service.in | 10 +++ systemd/security-manager-master.socket | 13 ++++ systemd/security-manager-slave.service.in | 9 +++ systemd/security-manager-slave.socket | 10 +++ systemd/security-manager.service.in | 2 + systemd/security-manager.socket | 4 + 18 files changed, 363 insertions(+), 21 deletions(-) create mode 100644 src/server/service/include/master-service.h create mode 100644 src/server/service/master-service.cpp create mode 100644 systemd/security-manager-master.service.in create mode 100644 systemd/security-manager-master.socket create mode 100644 systemd/security-manager-slave.service.in create mode 100644 systemd/security-manager-slave.socket diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 5269334..d6d259b 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -87,6 +87,8 @@ cp LICENSE %{buildroot}%{_datadir}/license/libsecurity-manager-client mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants ln -s ../security-manager.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager.socket +ln -s ../security-manager-master.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager-master.socket +ln -s ../security-manager-slave.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager-slave.socket %clean rm -rf %{buildroot} @@ -136,7 +138,11 @@ fi %{_libdir}/libsecurity-manager-commons.so.* %attr(-,root,root) %{_unitdir}/security-manager.* +%attr(-,root,root) %{_unitdir}/security-manager-master.* +%attr(-,root,root) %{_unitdir}/security-manager-slave.* %attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager.* +%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager-master.* +%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager-slave.* %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db-journal %{_datadir}/license/%{name} diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 9f3b11b..8360a26 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -120,6 +120,8 @@ struct user_req { namespace SecurityManager { extern char const * const SERVICE_SOCKET; +extern char const * const MASTER_SERVICE_SOCKET; +extern char const * const SLAVE_SERVICE_SOCKET; enum class SecurityModuleCall { diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index 827496a..fa999b6 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -35,6 +35,17 @@ namespace SecurityManager { namespace ServiceImpl { /** + * Retrieves ID (UID and PID) of peer connected to socket + * + * @param[in] Socket file descriptor + * @param[out] UID of connected peer. Function does not modify the variable if ID retrieval fails. + * @param[out] PID of connected peer. Function does not modify the variable if ID retrieval fails. + * + * @return True if peer ID was successfully retrieved, false otherwise. + */ +bool getPeerID(int sock, uid_t &uid, pid_t &pid); + +/** * Process application installation request. * * @param[in] req installation request diff --git a/src/common/protocols.cpp b/src/common/protocols.cpp index 798b9d6..eac619a 100644 --- a/src/common/protocols.cpp +++ b/src/common/protocols.cpp @@ -32,6 +32,10 @@ namespace SecurityManager { char const * const SERVICE_SOCKET = SOCKET_PATH_PREFIX "security-manager.socket"; +char const * const MASTER_SERVICE_SOCKET = + SOCKET_PATH_PREFIX "security-manager-master.socket"; +char const * const SLAVE_SERVICE_SOCKET = + SOCKET_PATH_PREFIX "security-manager-slave.socket"; } // namespace SecurityManager diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 7fd621c..20ee7a9 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,20 @@ static inline bool isSubDir(const char *parent, const char *subdir) return (*subdir == '/'); } +bool getPeerID(int sock, uid_t &uid, pid_t &pid) +{ + struct ucred cr; + socklen_t len = sizeof(cr); + + if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) { + uid = cr.uid; + pid = cr.pid; + return true; + } + + return false; +} + static bool getUserAppDir(const uid_t &uid, std::string &userAppDir) { struct tzplatform_context *tz_ctx = nullptr; diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 753eb96..8890aa3 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -3,7 +3,7 @@ PKG_CHECK_MODULES(SERVER_DEP libsystemd-daemon ) -FIND_PACKAGE(Boost REQUIRED) +FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options) FIND_PACKAGE(Threads REQUIRED) INCLUDE_DIRECTORIES(SYSTEM @@ -27,6 +27,7 @@ SET(SERVER_SOURCES ${SERVER_PATH}/main/server-main.cpp ${SERVER_PATH}/service/base-service.cpp ${SERVER_PATH}/service/service.cpp + ${SERVER_PATH}/service/master-service.cpp ) ADD_EXECUTABLE(${TARGET_SERVER} ${SERVER_SOURCES}) @@ -39,6 +40,7 @@ TARGET_LINK_LIBRARIES(${TARGET_SERVER} ${TARGET_COMMON} ${CMAKE_THREAD_LIBS_INIT} ${SERVER_DEP_LIBRARIES} + ${Boost_LIBRARIES} ) INSTALL(TARGETS ${TARGET_SERVER} DESTINATION ${BIN_INSTALL_DIR}) diff --git a/src/server/main/server-main.cpp b/src/server/main/server-main.cpp index c9609e2..f8e1f71 100644 --- a/src/server/main/server-main.cpp +++ b/src/server/main/server-main.cpp @@ -28,22 +28,30 @@ #include #include +#include +#include + #include #include #include +#include + +namespace po = boost::program_options; IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem); -#define REGISTER_SOCKET_SERVICE(manager, service) \ - registerSocketService(manager, #service) +#define REGISTER_SOCKET_SERVICE(manager, service, allocator) \ + registerSocketService(manager, #service, allocator) template -bool registerSocketService(SecurityManager::SocketManager &manager, const std::string& serviceName) +bool registerSocketService(SecurityManager::SocketManager &manager, + const std::string& serviceName, + const std::function& serviceAllocator) { T *service = NULL; try { - service = new T(); + service = serviceAllocator(); service->Create(); manager.RegisterSocketService(service); return true; @@ -62,12 +70,59 @@ bool registerSocketService(SecurityManager::SocketManager &manager, const std::s return false; } -int main(void) { - +int main(int argc, char* argv[]) +{ UNHANDLED_EXCEPTION_HANDLER_BEGIN { + // initialize logging SecurityManager::Singleton::Instance().SetTag("SECURITY_MANAGER"); + // parse arguments + bool masterMode = false, slaveMode = false; + po::options_description optDesc("Allowed options"); + + optDesc.add_options() + ("help,h", "Print this help message") + ("master,m", "Enable master mode") + ("slave,s", "Enable slave mode") + ; + + po::variables_map vm; + po::basic_parsed_options parsed = + po::command_line_parser(argc, argv).options(optDesc).allow_unregistered().run(); + + std::vector unrecognizedOptions = + po::collect_unrecognized(parsed.options, po::include_positional); + + if (!unrecognizedOptions.empty()) { + std::cerr << "Unrecognized options: "; + + for (auto& uo : unrecognizedOptions) { + std::cerr << ' ' << uo; + } + + std::cerr << std::endl << std::endl; + std::cerr << optDesc << std::endl; + + return EXIT_FAILURE; + } + + po::store(parsed, vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << optDesc << std::endl; + return EXIT_SUCCESS; + } + + masterMode = vm.count("master") > 0; + slaveMode = vm.count("slave") > 0; + + if (masterMode && slaveMode) { + LogError("Cannot be both master and slave!"); + return EXIT_FAILURE; + } + SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE, true); @@ -77,15 +132,24 @@ int main(void) { sigaddset(&mask, SIGPIPE); if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL)) { LogError("Error in pthread_sigmask"); - return 1; + return EXIT_FAILURE; } LogInfo("Start!"); SecurityManager::SocketManager manager; - if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service)) { - LogError("Unable to create socket service. Exiting."); - return EXIT_FAILURE; + if (masterMode) { + if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::MasterService, + []() { return new SecurityManager::MasterService(); } )) { + LogError("Unable to create master socket service. Exiting."); + return EXIT_FAILURE; + } + } else { + if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service, + [&slaveMode]() { return new SecurityManager::Service(slaveMode); } )) { + LogError("Unable to create socket service. Exiting."); + return EXIT_FAILURE; + } } manager.MainLoop(); @@ -94,5 +158,5 @@ int main(void) { return EXIT_FAILURE; } UNHANDLED_EXCEPTION_HANDLER_END - return 0; + return EXIT_SUCCESS; } diff --git a/src/server/service/include/master-service.h b/src/server/service/include/master-service.h new file mode 100644 index 0000000..170bfd9 --- /dev/null +++ b/src/server/service/include/master-service.h @@ -0,0 +1,61 @@ +/* + * 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 master-service.h + * @author Lukasz Kostyra + * @author Rafal Krypa + * @brief Implementation of security-manager master service + */ + +#ifndef _SECURITY_MANAGER_MASTER_SERVICE_ +#define _SECURITY_MANAGER_MASTER_SERVICE_ + +#include "base-service.h" + +namespace SecurityManager { + +class MasterServiceException +{ +public: + DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InvalidAction) +}; + +class MasterService : + public SecurityManager::BaseService +{ +public: + MasterService(); + ServiceDescriptionVector GetServiceDescription(); + +private: + + /** + * Handle request from a client + * + * @param conn Socket connection information + * @param buffer Raw received data buffer + * @param interfaceID identifier used to distinguish source socket + * @return true on success + */ + bool processOne(const ConnectionID &conn, MessageBuffer &buffer, InterfaceID interfaceID); +}; + +} // namespace SecurityManager + +#endif // _SECURITY_MANAGER_MASTER_SERVICE_ diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 883c989..765d0d0 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -40,10 +40,12 @@ class Service : public SecurityManager::BaseService { public: - Service(); + Service(const bool isSlave); ServiceDescriptionVector GetServiceDescription(); private: + const bool m_isSlave; + /** * Handle request from a client * diff --git a/src/server/service/master-service.cpp b/src/server/service/master-service.cpp new file mode 100644 index 0000000..2afae00 --- /dev/null +++ b/src/server/service/master-service.cpp @@ -0,0 +1,111 @@ +/* + * 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 master-service.cpp + * @author Lukasz Kostyra + * @author Rafal Krypa + * @brief Implementation of security-manager master service. + */ + +#include + +#include +#include + +#include "protocols.h" +#include "master-service.h" +#include "service_impl.h" + +namespace SecurityManager { + +const InterfaceID IFACE = 1; + +MasterService::MasterService() +{ +} + +GenericSocketService::ServiceDescriptionVector MasterService::GetServiceDescription() +{ + return ServiceDescriptionVector { + {MASTER_SERVICE_SOCKET, "security-manager-master", IFACE}, + }; +} + +bool MasterService::processOne(const ConnectionID &conn, MessageBuffer &buffer, + InterfaceID interfaceID) +{ + LogDebug("Iteration begin. Interface = " << interfaceID); + + //waiting for all data + if (!buffer.Ready()) { + return false; + } + + MessageBuffer send; + bool retval = false; + + uid_t uid; + pid_t pid; + + if (!ServiceImpl::getPeerID(conn.sock, uid, pid)) { + LogError("Closing socket because of error: unable to get peer's uid and pid"); + m_serviceManager->Close(conn); + return false; + } + + if (IFACE == interfaceID) { + Try { + // deserialize API call type + int call_type_int; + Deserialization::Deserialize(buffer, call_type_int); + SecurityModuleCall call_type = static_cast(call_type_int); + + switch (call_type) { + default: + LogError("Invalid call: " << call_type_int); + Throw(MasterServiceException::InvalidAction); + } + // if we reach this point, the protocol is OK + retval = true; + } Catch (MessageBuffer::Exception::Base) { + LogError("Broken protocol."); + } Catch (MasterServiceException::Base) { + LogError("Broken protocol."); + } catch (const std::exception &e) { + LogError("STD exception " << e.what()); + } catch (...) { + LogError("Unknown exception"); + } + } + else { + LogError("Wrong interface"); + } + + if (retval) { + //send response + m_serviceManager->Write(conn, send.Pop()); + } else { + LogError("Closing socket because of error"); + m_serviceManager->Close(conn); + } + + return retval; +} + + +} // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index e0925b1..522356f 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -37,19 +37,29 @@ namespace SecurityManager { const InterfaceID IFACE = 1; -Service::Service() +Service::Service(const bool isSlave): + m_isSlave(isSlave) { } GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription() { - return ServiceDescriptionVector { - {SERVICE_SOCKET, /* path */ - "*", /* smackLabel label (not used, we rely on systemd) */ - IFACE, /* InterfaceID */ - false, /* useSendMsg */ - true}, /* systemdOnly */ - }; + if (m_isSlave) + return ServiceDescriptionVector { + {SLAVE_SERVICE_SOCKET, /* path */ + "*", /* smackLabel label (not used, we rely on systemd) */ + IFACE, /* InterfaceID */ + false, /* useSendMsg */ + true}, /* systemdOnly */ + }; + else + return ServiceDescriptionVector { + {SERVICE_SOCKET, /* path */ + "*", /* smackLabel label (not used, we rely on systemd) */ + IFACE, /* InterfaceID */ + false, /* useSendMsg */ + true}, /* systemdOnly */ + }; } static bool getPeerID(int sock, uid_t &uid, pid_t &pid, std::string &smackLabel) diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt index 90c0ec1..02814a5 100644 --- a/systemd/CMakeLists.txt +++ b/systemd/CMakeLists.txt @@ -1,8 +1,14 @@ CONFIGURE_FILE(security-manager.service.in security-manager.service @ONLY) +CONFIGURE_FILE(security-manager-master.service.in security-manager-master.service @ONLY) +CONFIGURE_FILE(security-manager-slave.service.in security-manager-slave.service @ONLY) INSTALL(FILES security-manager.service security-manager.socket + security-manager-master.service + security-manager-master.socket + security-manager-slave.service + security-manager-slave.socket DESTINATION ${SYSTEMD_INSTALL_DIR} ) diff --git a/systemd/security-manager-master.service.in b/systemd/security-manager-master.service.in new file mode 100644 index 0000000..ef14a57 --- /dev/null +++ b/systemd/security-manager-master.service.in @@ -0,0 +1,10 @@ +[Unit] +Description=Start the security manager master +ConditionVirtualization=!lxc +ConditionPathExists=/usr/share/.zones/enabled + +[Service] +Type=notify +ExecStart=@BIN_INSTALL_DIR@/security-manager --master + +Sockets=security-manager-master.socket diff --git a/systemd/security-manager-master.socket b/systemd/security-manager-master.socket new file mode 100644 index 0000000..d41eae0 --- /dev/null +++ b/systemd/security-manager-master.socket @@ -0,0 +1,13 @@ +[Socket] +ListenStream=/run/security-manager-master.socket +SocketMode=0700 +SmackLabelIPIn=System +SmackLabelIPOut=System +Service=security-manager-master.service + +[Unit] +ConditionVirtualization=!lxc +ConditionPathExists=/usr/share/.zones/enabled + +[Install] +WantedBy=sockets.target diff --git a/systemd/security-manager-slave.service.in b/systemd/security-manager-slave.service.in new file mode 100644 index 0000000..6eb7505 --- /dev/null +++ b/systemd/security-manager-slave.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=Start the security manager slave +ConditionVirtualization=lxc + +[Service] +Type=notify +ExecStart=@BIN_INSTALL_DIR@/security-manager --slave + +Sockets=security-manager-slave.socket diff --git a/systemd/security-manager-slave.socket b/systemd/security-manager-slave.socket new file mode 100644 index 0000000..8d0a2c6 --- /dev/null +++ b/systemd/security-manager-slave.socket @@ -0,0 +1,10 @@ +[Socket] +ListenStream=/run/security-manager-slave.socket +Symlinks=/run/security-manager.socket +SocketMode=0777 +SmackLabelIPIn=* +SmackLabelIPOut=@ +Service=security-manager-slave.service + +[Unit] +ConditionVirtualization=lxc diff --git a/systemd/security-manager.service.in b/systemd/security-manager.service.in index 23fd1b2..f15ab90 100644 --- a/systemd/security-manager.service.in +++ b/systemd/security-manager.service.in @@ -1,5 +1,7 @@ [Unit] Description=Start the security manager +ConditionVirtualization=!lxc +ConditionPathExists=!/usr/share/.zones/enabled [Service] Type=notify diff --git a/systemd/security-manager.socket b/systemd/security-manager.socket index af1c1da..95411e8 100644 --- a/systemd/security-manager.socket +++ b/systemd/security-manager.socket @@ -7,5 +7,9 @@ SmackLabelIPOut=@ # TODO: move to separate systemd service Service=security-manager.service +[Unit] +ConditionVirtualization=!lxc +ConditionPathExists=!/usr/share/.zones/enabled + [Install] WantedBy=sockets.target -- 2.7.4 From 9703e341cc614b519a3a57d9356c6e8d3ca2cc1a Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Mon, 17 Nov 2014 12:48:55 +0100 Subject: [PATCH 07/16] Extract communication functions to common library Since slave service will use the same functions as client library to send data, these are extracted in this commit and will be used in the next change. [Verification] Build, install, run tests. Change-Id: I4b9e11015c657066657f493e87d68958283bb947 --- src/client/client-common.cpp | 211 -------------------------- src/client/client-offline.cpp | 3 +- src/client/client-security-manager.cpp | 2 + src/client/include/client-common.h | 21 --- src/common/CMakeLists.txt | 1 + src/common/connection.cpp | 261 +++++++++++++++++++++++++++++++++ src/common/include/connection.h | 57 +++++++ src/server/service/service.cpp | 1 + 8 files changed, 324 insertions(+), 233 deletions(-) create mode 100644 src/common/connection.cpp create mode 100644 src/common/include/connection.h diff --git a/src/client/client-common.cpp b/src/client/client-common.cpp index 883ab8d..3051cbc 100644 --- a/src/client/client-common.cpp +++ b/src/client/client-common.cpp @@ -45,225 +45,14 @@ IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem); namespace { -const int POLL_TIMEOUT = -1; - void securityClientEnableLogSystem(void) { SecurityManager::Singleton::Instance().SetTag("SECURITY_MANAGER_CLIENT"); } -int waitForSocket(int sock, int event, int timeout) { - int retval; - pollfd desc[1]; - desc[0].fd = sock; - desc[0].events = event; - - while((-1 == (retval = poll(desc, 1, timeout))) && (errno == EINTR)) { - timeout >>= 1; - errno = 0; - } - - if (0 == retval) { - LogDebug("Poll timeout"); - } else if (-1 == retval) { - int err = errno; - LogError("Error in poll: " << strerror(err)); - } - return retval; -} - -class SockRAII { -public: - SockRAII() - : m_sock(-1) - {} - - virtual ~SockRAII() { - if (m_sock > -1) - close(m_sock); - } - - int Connect(char const * const interface) { - sockaddr_un clientAddr; - int flags; - - if (m_sock != -1) // guard - close(m_sock); - - m_sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (m_sock < 0) { - int err = errno; - LogError("Error creating socket: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - if ((flags = fcntl(m_sock, F_GETFL, 0)) < 0 || - fcntl(m_sock, F_SETFL, flags | O_NONBLOCK) < 0) - { - int err = errno; - LogError("Error in fcntl: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - memset(&clientAddr, 0, sizeof(clientAddr)); - - clientAddr.sun_family = AF_UNIX; - - if (strlen(interface) >= sizeof(clientAddr.sun_path)) { - LogError("Error: interface name " << interface << "is too long. Max len is:" << sizeof(clientAddr.sun_path)); - return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE; - } - - strcpy(clientAddr.sun_path, interface); - - LogDebug("ClientAddr.sun_path = " << interface); - - int retval = TEMP_FAILURE_RETRY(connect(m_sock, (struct sockaddr*)&clientAddr, SUN_LEN(&clientAddr))); - if ((retval == -1) && (errno == EINPROGRESS)) { - if (0 >= waitForSocket(m_sock, POLLOUT, POLL_TIMEOUT)) { - LogError("Error in waitForSocket."); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - int error = 0; - socklen_t len = sizeof(error); - retval = getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &error, &len); - - if (-1 == retval) { - int err = errno; - LogError("Error in getsockopt: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - if (error == EACCES) { - LogError("Access denied"); - return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED; - } - - if (error != 0) { - LogError("Error in connect: " << strerror(error)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - return SECURITY_MANAGER_API_SUCCESS; - } - - if (-1 == retval) { - int err = errno; - LogError("Error connecting socket: " << strerror(err)); - if (err == EACCES) - return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED; - if (err == ENOTSOCK) - return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE; - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - return SECURITY_MANAGER_API_SUCCESS; - } - - int Get() { - return m_sock; - } - -private: - int m_sock; -}; - } // namespace anonymous namespace SecurityManager { -int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv) { - int ret; - SockRAII sock; - ssize_t done = 0; - char buffer[2048]; - - if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) { - LogError("Error in SockRAII"); - return ret; - } - - while ((send.size() - done) > 0) { - if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) { - LogError("Error in poll(POLLOUT)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done)); - if (-1 == temp) { - int err = errno; - LogError("Error in write: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - done += temp; - } - - do { - if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) { - LogError("Error in poll(POLLIN)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - ssize_t temp = TEMP_FAILURE_RETRY(read(sock.Get(), buffer, 2048)); - if (-1 == temp) { - int err = errno; - LogError("Error in read: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - if (0 == temp) { - LogError("Read return 0/Connection closed by server(?)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - RawBuffer raw(buffer, buffer+temp); - recv.Push(raw); - } while(!recv.Ready()); - return SECURITY_MANAGER_API_SUCCESS; -} - -int sendToServerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr) { - int ret; - SockRAII sock; - ssize_t done = 0; - - if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) { - LogError("Error in SockRAII"); - return ret; - } - - while ((send.size() - done) > 0) { - if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) { - LogError("Error in poll(POLLOUT)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done)); - if (-1 == temp) { - int err = errno; - LogError("Error in write: " << strerror(err)); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - done += temp; - } - - if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) { - LogError("Error in poll(POLLIN)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - ssize_t temp = TEMP_FAILURE_RETRY(recvmsg(sock.Get(), &hdr, MSG_CMSG_CLOEXEC)); - - if (temp < 0) { - int err = errno; - LogError("Error in recvmsg(): " << strerror(err) << " errno: " << err); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - if (0 == temp) { - LogError("Read return 0/Connection closed by server(?)"); - return SECURITY_MANAGER_API_ERROR_SOCKET; - } - - return SECURITY_MANAGER_API_SUCCESS; -} - int try_catch(const std::function& func) { try { diff --git a/src/client/client-offline.cpp b/src/client/client-offline.cpp index e442c2f..d60911d 100644 --- a/src/client/client-offline.cpp +++ b/src/client/client-offline.cpp @@ -22,12 +22,13 @@ * @brief Helper class for client "off-line" mode detection */ +#include #include #include #include +#include #include #include -#include "client-offline.h" namespace SecurityManager { diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 74a6b30..4d6fecb 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 diff --git a/src/client/include/client-common.h b/src/client/include/client-common.h index c7d18a4..b82f6a5 100644 --- a/src/client/include/client-common.h +++ b/src/client/include/client-common.h @@ -26,34 +26,13 @@ #ifndef _SECURITY_MANAGER_CLIENT_ #define _SECURITY_MANAGER_CLIENT_ -#include #include -#include - #define SECURITY_MANAGER_API __attribute__((visibility("default"))) #define SECURITY_MANAGER_UNUSED __attribute__((unused)) -extern "C" { - struct msghdr; -} - namespace SecurityManager { -typedef std::vector RawBuffer; - -int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv); - -/* - * sendToServerAncData is special case when we want to receive file descriptor - * passed by Security Manager on behalf of calling process. We can't get it with - * MessageBuffer. - * - * This function should be called _ONLY_ in this particular case. - * - */ -int sendToManagerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr); - /* * Decorator function that performs frequently repeated exception handling in * SS client API functions. Accepts lambda expression as an argument. diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2da9c3e..6571e64 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -41,6 +41,7 @@ SET(COMMON_SOURCES ${DPL_PATH}/core/src/string.cpp ${DPL_PATH}/db/src/naive_synchronization_object.cpp ${DPL_PATH}/db/src/sql_connection.cpp + ${COMMON_PATH}/connection.cpp ${COMMON_PATH}/cynara.cpp ${COMMON_PATH}/file-lock.cpp ${COMMON_PATH}/protocols.cpp diff --git a/src/common/connection.cpp b/src/common/connection.cpp new file mode 100644 index 0000000..e4dc9ee --- /dev/null +++ b/src/common/connection.cpp @@ -0,0 +1,261 @@ +/* + * 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 connection.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief This file is implementation of common connection functions. + */ + +#include "connection.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +namespace { + +const int POLL_TIMEOUT = -1; + +int waitForSocket(int sock, int event, int timeout) { + int retval; + pollfd desc[1]; + desc[0].fd = sock; + desc[0].events = event; + + while((-1 == (retval = poll(desc, 1, timeout))) && (errno == EINTR)) { + timeout >>= 1; + errno = 0; + } + + if (0 == retval) { + LogDebug("Poll timeout"); + } else if (-1 == retval) { + int err = errno; + LogError("Error in poll: " << strerror(err)); + } + return retval; +} + +class SockRAII { +public: + SockRAII() + : m_sock(-1) + {} + + virtual ~SockRAII() { + if (m_sock > -1) + close(m_sock); + } + + int Connect(char const * const interface) { + sockaddr_un clientAddr; + int flags; + + if (m_sock != -1) // guard + close(m_sock); + + m_sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (m_sock < 0) { + int err = errno; + LogError("Error creating socket: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + if ((flags = fcntl(m_sock, F_GETFL, 0)) < 0 || + fcntl(m_sock, F_SETFL, flags | O_NONBLOCK) < 0) + { + int err = errno; + LogError("Error in fcntl: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + memset(&clientAddr, 0, sizeof(clientAddr)); + + clientAddr.sun_family = AF_UNIX; + + if (strlen(interface) >= sizeof(clientAddr.sun_path)) { + LogError("Error: interface name " << interface << "is too long. Max len is:" << sizeof(clientAddr.sun_path)); + return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE; + } + + strcpy(clientAddr.sun_path, interface); + + LogDebug("ClientAddr.sun_path = " << interface); + + 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)) { + LogError("Error in waitForSocket."); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + int error = 0; + socklen_t len = sizeof(error); + retval = getsockopt(m_sock, SOL_SOCKET, SO_ERROR, &error, &len); + + if (-1 == retval) { + int err = errno; + LogError("Error in getsockopt: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + if (error == EACCES) { + LogError("Access denied"); + return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED; + } + + if (error != 0) { + LogError("Error in connect: " << strerror(error)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + return SECURITY_MANAGER_API_SUCCESS; + } + + if (-1 == retval) { + int err = errno; + LogError("Error connecting socket: " << strerror(err)); + if (err == EACCES) + return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED; + if (err == ENOTSOCK) + return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE; + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + return SECURITY_MANAGER_API_SUCCESS; + } + + int Get() { + return m_sock; + } + +private: + int m_sock; +}; + +} // namespace anonymous + +namespace SecurityManager { + +int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv) { + int ret; + SockRAII sock; + ssize_t done = 0; + char buffer[2048]; + + if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) { + LogError("Error in SockRAII"); + return ret; + } + + while ((send.size() - done) > 0) { + if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) { + LogError("Error in poll(POLLOUT)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done)); + if (-1 == temp) { + int err = errno; + LogError("Error in write: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + done += temp; + } + + do { + if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) { + LogError("Error in poll(POLLIN)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + ssize_t temp = TEMP_FAILURE_RETRY(read(sock.Get(), buffer, 2048)); + if (-1 == temp) { + int err = errno; + LogError("Error in read: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + if (0 == temp) { + LogError("Read return 0/Connection closed by server(?)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + RawBuffer raw(buffer, buffer+temp); + recv.Push(raw); + } while(!recv.Ready()); + return SECURITY_MANAGER_API_SUCCESS; +} + +int sendToServerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr) { + int ret; + SockRAII sock; + ssize_t done = 0; + + if (SECURITY_MANAGER_API_SUCCESS != (ret = sock.Connect(interface))) { + LogError("Error in SockRAII"); + return ret; + } + + while ((send.size() - done) > 0) { + if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) { + LogError("Error in poll(POLLOUT)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done)); + if (-1 == temp) { + int err = errno; + LogError("Error in write: " << strerror(err)); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + done += temp; + } + + if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) { + LogError("Error in poll(POLLIN)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + ssize_t temp = TEMP_FAILURE_RETRY(recvmsg(sock.Get(), &hdr, MSG_CMSG_CLOEXEC)); + + if (temp < 0) { + int err = errno; + LogError("Error in recvmsg(): " << strerror(err) << " errno: " << err); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + if (0 == temp) { + LogError("Read return 0/Connection closed by server(?)"); + return SECURITY_MANAGER_API_ERROR_SOCKET; + } + + return SECURITY_MANAGER_API_SUCCESS; +} + +} // namespace SecurityManager diff --git a/src/common/include/connection.h b/src/common/include/connection.h new file mode 100644 index 0000000..77967c4 --- /dev/null +++ b/src/common/include/connection.h @@ -0,0 +1,57 @@ +/* + * 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 sock-raii.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief This file constains declarations of connection-related functions + * used in security manager. + */ + +#ifndef _SECURITY_MANAGER_CONNECTION_ +#define _SECURITY_MANAGER_CONNECTION_ + +#include +#include + +#include + +extern "C" { + struct msghdr; +} + +namespace SecurityManager { + +typedef std::vector RawBuffer; + +int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv); + +/* + * sendToServerAncData is special case when we want to receive file descriptor + * passed by Security Manager on behalf of calling process. We can't get it with + * MessageBuffer. + * + * This function should be called _ONLY_ in this particular case. + * + */ +int sendToManagerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr); + +} // namespace SecurityManager + +#endif // _SECURITY_MANAGER_CONNECTION_ diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 522356f..334ce19 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -29,6 +29,7 @@ #include #include +#include "connection.h" #include "protocols.h" #include "service.h" #include "service_impl.h" -- 2.7.4 From 57fd245f1331b42917f2875241b617b4e2515b83 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 17 Apr 2015 11:18:32 +0200 Subject: [PATCH 08/16] cynara: handle additional error codes from Cynara API These error codes appeared in Cynara API after security-manager was integrated with it. Change-Id: Iba495040bd8bbb9a879a0fd27e880bb7547ed583 Signed-off-by: Rafal Krypa --- src/common/cynara.cpp | 8 ++++++++ src/common/include/cynara.h | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 29b06bc..14acb36 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -212,12 +212,20 @@ static bool checkCynaraError(int result, const std::string &msg) return true; case CYNARA_API_ACCESS_DENIED: return false; + case CYNARA_API_MAX_PENDING_REQUESTS: + ThrowMsg(CynaraException::MaxPendingRequests, msg); case CYNARA_API_OUT_OF_MEMORY: ThrowMsg(CynaraException::OutOfMemory, msg); case CYNARA_API_INVALID_PARAM: ThrowMsg(CynaraException::InvalidParam, msg); case CYNARA_API_SERVICE_NOT_AVAILABLE: ThrowMsg(CynaraException::ServiceNotAvailable, msg); + case CYNARA_API_METHOD_NOT_SUPPORTED: + ThrowMsg(CynaraException::MethodNotSupported, msg); + case CYNARA_API_OPERATION_NOT_ALLOWED: + ThrowMsg(CynaraException::OperationNotAllowed, msg); + case CYNARA_API_OPERATION_FAILED: + ThrowMsg(CynaraException::OperationFailed, msg); case CYNARA_API_BUCKET_NOT_FOUND: ThrowMsg(CynaraException::BucketNotFound, msg); default: diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index a75e414..3e9a818 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -51,11 +51,15 @@ class CynaraException { public: DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, MaxPendingRequests) DECLARE_EXCEPTION_TYPE(Base, OutOfMemory) DECLARE_EXCEPTION_TYPE(Base, InvalidParam) DECLARE_EXCEPTION_TYPE(Base, ServiceNotAvailable) - DECLARE_EXCEPTION_TYPE(Base, UnknownError) + DECLARE_EXCEPTION_TYPE(Base, MethodNotSupported) + DECLARE_EXCEPTION_TYPE(Base, OperationNotAllowed) + DECLARE_EXCEPTION_TYPE(Base, OperationFailed) DECLARE_EXCEPTION_TYPE(Base, BucketNotFound) + DECLARE_EXCEPTION_TYPE(Base, UnknownError) }; struct CynaraAdminPolicy : cynara_admin_policy -- 2.7.4 From 0a18023646c011eeb05abea4ec12fa1c5229728a Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 17 Apr 2015 11:17:02 +0200 Subject: [PATCH 09/16] cynara: rewrite class using cynara async API for parallel processing Cynara class method check() can now be called in parallel by multiple threads. Each call blocks until it gets a response. This is a first step toward making security-manager multi-threaded, for processing multiple requests in parallel. Cynara class remains a singleton for now, but eventually there will be single instance constructed (and destructed) from the main thread and called for checks from separate threads processing user requests. Change-Id: Ie1f55b9610caf45dc0df06dbd713070d39ccac07 Signed-off-by: Rafal Krypa --- packaging/security-manager.spec | 2 +- src/common/CMakeLists.txt | 2 +- src/common/cynara.cpp | 174 ++++++++++++++++++++++++++++++++++++++-- src/common/include/cynara.h | 29 ++++++- 4 files changed, 195 insertions(+), 12 deletions(-) diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index d6d259b..8baa231 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -20,7 +20,7 @@ BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(db-util) BuildRequires: pkgconfig(cynara-admin) -BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(cynara-client-async) BuildRequires: boost-devel %{?systemd_requires} diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 6571e64..32b3f77 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -7,7 +7,7 @@ PKG_CHECK_MODULES(COMMON_DEP libsmack db-util cynara-admin - cynara-client + cynara-client-async ) FIND_PACKAGE(Boost REQUIRED) diff --git a/src/common/cynara.cpp b/src/common/cynara.cpp index 14acb36..30f0777 100644 --- a/src/common/cynara.cpp +++ b/src/common/cynara.cpp @@ -544,14 +544,39 @@ int CynaraAdmin::GetPrivilegeManagerMaxLevel(const std::string &label, const std Cynara::Cynara() { + int ret; + + ret = eventfd(0, 0); + if (ret == -1) { + LogError("Error while creating eventfd: " << strerror(errno)); + ThrowMsg(CynaraException::UnknownError, "Error while creating eventfd"); + } + + // Poll the eventfd for reading + pollFds[0].fd = ret; + pollFds[0].events = POLLIN; + + // Temporary, will be replaced by cynara fd when available + pollFds[1].fd = pollFds[0].fd; + pollFds[1].events = 0; + checkCynaraError( - cynara_initialize(&m_Cynara, nullptr), + cynara_async_initialize(&cynara, nullptr, &Cynara::statusCallback, &(pollFds[1])), "Cannot connect to Cynara policy interface."); + + thread = std::thread(&Cynara::run, this); } Cynara::~Cynara() { - cynara_finish(m_Cynara); + LogDebug("Sending terminate event to Cynara thread"); + terminate.store(true); + threadNotifyPut(); + thread.join(); + + // Critical section + std::lock_guard guard(mutex); + cynara_async_finish(cynara); } Cynara &Cynara::getInstance() @@ -560,13 +585,150 @@ Cynara &Cynara::getInstance() return cynara; } +void Cynara::threadNotifyPut() +{ + int ret = eventfd_write(pollFds[0].fd, 1); + if (ret == -1) + LogError("Unexpected error while writing to eventfd: " << strerror(errno)); +} + +void Cynara::threadNotifyGet() +{ + eventfd_t value; + int ret = eventfd_read(pollFds[0].fd, &value); + if (ret == -1) + LogError("Unexpected error while reading from eventfd: " << strerror(errno)); +} + +void Cynara::statusCallback(int oldFd, int newFd, cynara_async_status status, + void *ptr) +{ + auto cynaraFd = static_cast(ptr); + + LogDebug("Cynara status callback. " << + "Status = " << status << ", oldFd = " << oldFd << ", newFd = " << newFd); + + if (newFd == -1) { + cynaraFd->events = 0; + } else { + cynaraFd->fd = newFd; + + switch (status) { + case CYNARA_STATUS_FOR_READ: + cynaraFd->events = POLLIN; + break; + + case CYNARA_STATUS_FOR_RW: + cynaraFd->events = POLLIN | POLLOUT; + break; + } + } +} + +void Cynara::responseCallback(cynara_check_id checkId, + cynara_async_call_cause cause, int response, void *ptr) +{ + LogDebug("Response for received for Cynara check id: " << checkId); + + auto promise = static_cast*>(ptr); + + switch (cause) { + case CYNARA_CALL_CAUSE_ANSWER: + LogDebug("Cynara cause: ANSWER: " << response); + promise->set_value(response); + break; + + case CYNARA_CALL_CAUSE_CANCEL: + LogDebug("Cynara cause: CANCEL"); + promise->set_value(CYNARA_API_ACCESS_DENIED); + break; + + case CYNARA_CALL_CAUSE_FINISH: + LogDebug("Cynara cause: FINISH"); + promise->set_value(CYNARA_API_ACCESS_DENIED); + break; + + case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE: + LogError("Cynara cause: SERVICE_NOT_AVAILABLE"); + + try { + ThrowMsg(CynaraException::ServiceNotAvailable, + "Cynara service not available"); + } catch (...) { + promise->set_exception(std::current_exception()); + } + break; + } +} + +void Cynara::run() +{ + LogInfo("Cynara thread started"); + while (true) { + int ret = poll(pollFds, 2, -1); + if (ret == -1) { + if (errno != EINTR) + LogError("Unexpected error returned by poll: " << strerror(errno)); + continue; + } + + // Check eventfd for termination signal + if (pollFds[0].revents) { + threadNotifyGet(); + if (terminate.load()) { + LogInfo("Cynara thread terminated"); + return; + } + } + + // Check if Cynara fd is ready for processing + try { + if (pollFds[1].revents) { + // Critical section + std::lock_guard guard(mutex); + + checkCynaraError(cynara_async_process(cynara), + "Unexpected error returned by cynara_async_process"); + } + } catch (const CynaraException::Base &e) { + LogError("Error while processing Cynara events: " << e.DumpToString()); + } + } +} + bool Cynara::check(const std::string &label, const std::string &privilege, const std::string &user, const std::string &session) { - return checkCynaraError( - cynara_check(m_Cynara, - label.c_str(), session.c_str(), user.c_str(), privilege.c_str()), - "Cannot check permission with Cynara."); + LogDebug("check: client = " << label << ", user = " << user << + ", privilege = " << privilege << ", session = " << session); + + std::promise promise; + auto future = promise.get_future(); + + // Critical section + { + std::lock_guard guard(mutex); + + int ret = cynara_async_check_cache(cynara, + label.c_str(), session.c_str(), user.c_str(), privilege.c_str()); + + if (ret != CYNARA_API_CACHE_MISS) + return checkCynaraError(ret, "Error while checking Cynara cache"); + + LogDebug("Cynara cache miss"); + + cynara_check_id check_id; + checkCynaraError( + cynara_async_create_request(cynara, + label.c_str(), session.c_str(), user.c_str(), privilege.c_str(), + &check_id, &Cynara::responseCallback, &promise), + "Cannot check permission with Cynara."); + + threadNotifyPut(); + LogDebug("Waiting for response to Cynara query id " << check_id); + } + + return future.get(); } } // namespace SecurityManager diff --git a/src/common/include/cynara.h b/src/common/include/cynara.h index 3e9a818..aa0ed60 100644 --- a/src/common/include/cynara.h +++ b/src/common/include/cynara.h @@ -24,12 +24,18 @@ #ifndef _SECURITY_MANAGER_CYNARA_ #define _SECURITY_MANAGER_CYNARA_ -#include +#include #include #include #include #include #include +#include +#include +#include + +#include +#include #include "security-manager.h" @@ -293,7 +299,7 @@ private: class Cynara { public: - virtual ~Cynara(); + ~Cynara(); static Cynara &getInstance(); @@ -311,9 +317,24 @@ public: private: Cynara(); - struct cynara *m_Cynara; -}; + static void statusCallback(int oldFd, int newFd, + cynara_async_status status, void *ptr); + + static void responseCallback(cynara_check_id checkId, + cynara_async_call_cause cause, int response, void *ptr); + + void run(); + + void threadNotifyPut(); + void threadNotifyGet(); + + cynara_async *cynara; + struct pollfd pollFds[2]; + std::mutex mutex; + std::thread thread; + std::atomic terminate{false}; +}; } // namespace SecurityManager -- 2.7.4 From f868403e420691aa3c65173e5c75d9c7351c7d1d Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 27 Nov 2014 17:14:08 +0100 Subject: [PATCH 10/16] Implement master and slave mode Final patch with master and slave mode implementation. Every container should have its own privilege DB - slave will delegate calls to SMACK and to Cynara Administrative Socket to master. [Verification] Build, install, run tests on hosts - no changes should occur. Run tests in containers: * Run a container * bind-mount /run/security-manager-master.socket and /run/cynara/cynara.socket to container * Run tests Keep in mind, some might fail due to tests not being container-aware. Change-Id: Ibd1d884ad7dba6a15ebaa068c2c216a88562eb50 --- src/client/client-security-manager.cpp | 18 +- src/common/CMakeLists.txt | 2 + src/common/include/master-req.h | 143 +++++++++++++ src/common/include/protocols.h | 13 ++ src/common/include/service_impl.h | 16 +- src/common/include/smack-labels.h | 24 +++ src/common/include/smack-rules.h | 30 ++- src/common/include/zone-utils.h | 86 ++++++++ src/common/master-req.cpp | 202 ++++++++++++++++++ src/common/service_impl.cpp | 192 +++++++++++++---- src/common/smack-labels.cpp | 22 +- src/common/smack-rules.cpp | 43 ++-- src/common/zone-utils.cpp | 110 ++++++++++ src/server/CMakeLists.txt | 1 + src/server/service/include/master-service.h | 78 +++++++ src/server/service/master-service.cpp | 305 +++++++++++++++++++++++++++- src/server/service/service.cpp | 40 +++- 17 files changed, 1244 insertions(+), 81 deletions(-) create mode 100644 src/common/include/master-req.h create mode 100644 src/common/include/zone-utils.h create mode 100644 src/common/master-req.cpp create mode 100644 src/common/zone-utils.cpp diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 4d6fecb..5a8c4d8 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -168,7 +169,7 @@ int security_manager_app_install(const app_inst_req *p_req) int retval; ClientOffline offlineMode; if (offlineMode.isOffline()) { - retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid()); + retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid(), false); } else { MessageBuffer send, recv; @@ -365,8 +366,18 @@ int security_manager_set_process_label_from_appid(const char *app_id) if (smack_smackfs_path() == NULL) return SECURITY_MANAGER_SUCCESS; + // FIXME Below modifications related to zones are temporary. Remove when Smack Namespaces + // are implemented. + std::string zoneId; + if (!getZoneIdFromPid(getpid(), zoneId)) { + LogError("Failed to get ID of zone"); + return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE; + } + try { - appLabel = SecurityManager::SmackLabels::generateAppLabel(app_id); + appLabel = SecurityManager::zoneSmackLabelGenerate( + SecurityManager::SmackLabels::generateAppLabel(app_id), zoneId); + } catch (...) { LogError("Failed to generate smack label for appId: " << app_id); return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT; @@ -566,7 +577,8 @@ int security_manager_user_add(const user_req *p_req) int retval; ClientOffline offlineMode; if (offlineMode.isOffline()) { - retval = SecurityManager::ServiceImpl::userAdd(p_req->uid, p_req->utype, geteuid()); + retval = SecurityManager::ServiceImpl::userAdd(p_req->uid, p_req->utype, geteuid(), + false); } else { MessageBuffer send, recv; //server is working diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 32b3f77..2994af5 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -46,11 +46,13 @@ SET(COMMON_SOURCES ${COMMON_PATH}/file-lock.cpp ${COMMON_PATH}/protocols.cpp ${COMMON_PATH}/message-buffer.cpp + ${COMMON_PATH}/master-req.cpp ${COMMON_PATH}/privilege_db.cpp ${COMMON_PATH}/smack-labels.cpp ${COMMON_PATH}/smack-rules.cpp ${COMMON_PATH}/smack-check.cpp ${COMMON_PATH}/service_impl.cpp + ${COMMON_PATH}/zone-utils.cpp ) ADD_LIBRARY(${TARGET_COMMON} SHARED ${COMMON_SOURCES}) diff --git a/src/common/include/master-req.h b/src/common/include/master-req.h new file mode 100644 index 0000000..9890728 --- /dev/null +++ b/src/common/include/master-req.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2015 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 master-req.h + * @author Lukasz Kostyra + * @brief Master request calls declaration + */ + +#ifndef _SECURITY_MANAGER_MASTER_REQ_ +#define _SECURITY_MANAGER_MASTER_REQ_ + +#include +#include + +#include "protocols.h" + + +namespace SecurityManager { +namespace MasterReq { + +/** + * Forwards Cynara Policy Update request to Master Service. + * + * @param[in] appID Application ID + * @param[in] uidstr String containing user identifier + * @param[in] oldPkgPrivileges Previously enabled privileges for the package, + * Must be sorted and without duplicates + * @param[in] newPkgPrivileges Currently enabled privileges for the package, + * Must be sorted and without duplicates + * + * @see CynaraAdmin::UpdateAppPolicy + */ +int CynaraPolicyUpdate(const std::string &appId, const std::string &uidstr, + const std::vector &oldPkgPrivileges, + const std::vector &newPkgPrivileges); + +/** + * Forwards Cynara user initialization to Master service. + * + * @param[in] uidAdded New user UID + * @param[in] userType Type of user, enumerated in security-manager.h + * @return API return code, as defined in protocols.h + * + * @see CynaraAdmin::UserInit + */ +int CynaraUserInit(const uid_t uidAdded, int userType); + +/** + * Forwards Cynara user removal to Master service. + * + * @param[in] uidDeleted Removed user UID + * @return API return code, as defined in protocols.h + * + * @see CynaraAdmin::UserRemove + */ +int CynaraUserRemove(const uid_t uidDeleted); + +/** + * Forwards SMACK rule installation to Master service. + * + * @param[in] appId ID of application being removed + * @param[in] pkgId ID of package being removed + * @param[in] pkgContents A list of all applications in the package + * @return API return code, as defined in protocols.h + * + * @see SmackRules::installApplicationRules + */ +int SmackInstallRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents); + +/** + * Forwards SMACK rule removal to Master service. + * + * @param[in] appId ID of application being removed + * @param[in] pkgId ID of package being removed + * @param[in] pkgContents A list of all applications in the package + * @param[in] removePkg Flag stating if entire package should be removed + * @return API return code, as defined in protocols.h + * + * @see SmackRules::uninstallPackageRules, SmackRules::uninstallApplicationRules + */ +int SmackUninstallRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents, const bool removePkg); + +/** + * Forwards policyUpdate API to Master. Arguments are the same as policyUpdate. + * + * @return API return code, as defined in protocols.h + * + * @see ServiceImpl::policyUpdate + */ +int PolicyUpdate(const std::vector &policyEntries, uid_t uid, pid_t pid, + const std::string &smackLabel); + +/** + * Forwards getConfiguredPolicy API to Master. Arguments are the same as getConfiguredPolicy. + * + * @return API return code, as defined in protocols.h + * + * @see ServiceImpl::getConfiguredPolicy + */ +int GetConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid, + const std::string &smackLabel, std::vector &policyEntries); + +/** + * Forwards getPolicy API to Master. Arguments are the same as getPolicy. + * + * @return API return code, as defined in protocols.h + * + * @see ServiceImpl::getPolicy + */ +int GetPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, + std::vector &policyEntries); + +/** + * Forwards policyGetDesc API to Master. Arguments are the same as policyGetDesc. + * + * @return API return code, as defined in protocols.h + * + * @see ServiceImpl::policyGetDesc + */ +int PolicyGetDesc(std::vector &descriptions); + +} // namespace MasterReq +} // namespace SecurityManager + +#endif // _SECURITY_MANAGER_MASTER_REQ_ diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 8360a26..412db07 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -139,6 +139,19 @@ enum class SecurityModuleCall NOOP = 0x90, }; +enum class MasterSecurityModuleCall +{ + CYNARA_UPDATE_POLICY, + CYNARA_USER_INIT, + CYNARA_USER_REMOVE, + POLICY_UPDATE, + GET_CONFIGURED_POLICY, + GET_POLICY, + POLICY_GET_DESC, + SMACK_INSTALL_RULES, + SMACK_UNINSTALL_RULES, +}; + } // namespace SecurityManager using namespace SecurityManager; diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index fa999b6..a973c35 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -50,20 +50,22 @@ bool getPeerID(int sock, uid_t &uid, pid_t &pid); * * @param[in] req installation request * @param[in] uid id of the requesting user + * @param[in] isSlave Indicates if function should be called under slave mode * * @return API return code, as defined in protocols.h */ -int appInstall(const app_inst_req &req, uid_t uid); +int appInstall(const app_inst_req &req, uid_t uid, bool isSlave); /** * Process application uninstallation request. * * @param[in] req uninstallation request * @param[in] uid id of the requesting user + * @param[in] isSlave Indicates if function should be called under slave mode * * @return API return code, as defined in protocols.h */ -int appUninstall(const std::string &appId, uid_t uid); +int appUninstall(const std::string &appId, uid_t uid, bool isSlave); /** * Process package id query. @@ -86,11 +88,13 @@ int getPkgId(const std::string &appId, std::string &pkgId); * @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[in] isSlave Indicates if function should be called under slave mode * @param[out] gids returned set of allowed group ids * * @return API return code, as defined in protocols.h */ -int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids); +int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave, + std::unordered_set &gids); /** * Process user adding request. @@ -98,20 +102,22 @@ int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_ * @param[in] uidAdded uid of newly created user * @param[in] userType type of newly created user * @param[in] uid uid of requesting user + * @param[in] isSlave Indicates if function should be called under slave mode * * @return API return code, as defined in protocols.h */ -int userAdd(uid_t uidAdded, int userType, uid_t uid); +int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave); /** * Process user deletion request. * * @param[in] uidDeleted uid of removed user * @param[in] uid uid of requesting user + * @param[in] isSlave Indicates if function should be called under slave mode * * @return API return code, as defined in protocols.h */ -int userDelete(uid_t uidDeleted, uid_t uid); +int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave); /** * Update policy in Cynara - proper privilege: http://tizen.org/privilege/systemsettings.admin diff --git a/src/common/include/smack-labels.h b/src/common/include/smack-labels.h index f4f15f7..b454eff 100644 --- a/src/common/include/smack-labels.h +++ b/src/common/include/smack-labels.h @@ -47,6 +47,18 @@ void setupPath(const std::string &appId, const std::string &path, app_install_path_type pathType); /** + * Sets Smack labels on a directory and its contents, recursively. + * + * @param appId[in] application's identifier + * @param path[in] path to a file or directory to setup + * @param pathType[in] type of path to setup. See description of + * app_install_path_type in security-manager.h for details + * @param zoneId[in] ID of zone for which label should be set + */ +void setupPath(const std::string &appId, const std::string &path, + app_install_path_type pathType, const std::string &zoneId); + +/** * Sets Smack labels on a / and // * non-recursively * @@ -58,6 +70,18 @@ void setupCorrectPath(const std::string &pkgId, const std::string &appId, const std::string &basePath); /** + * Sets Smack labels on a / and // + * non-recursively + * + * @param pkgId[in] package identifier + * @param appId[in] application's identifier + * @param basePath[in] path + * @param zoneId[in] ID of zone for which label should be set + */ +void setupCorrectPath(const std::string &pkgId, const std::string &appId, + const std::string &basePath, const std::string &zoneId); + +/** * Generates application name for a label fetched from Cynara * * @param[in] label string to fetch application name for diff --git a/src/common/include/smack-rules.h b/src/common/include/smack-rules.h index 91446a7..5aadc12 100644 --- a/src/common/include/smack-rules.h +++ b/src/common/include/smack-rules.h @@ -45,8 +45,9 @@ public: const std::string &allowPermissions, const std::string &denyPermissions); void loadFromFile(const std::string &path); void addFromTemplate(const std::vector &templateRules, - const std::string &appId, const std::string &pkgId); - void addFromTemplateFile(const std::string &appId, const std::string &pkgId); + const std::string &appId, const std::string &pkgId, const std::string &zoneId); + void addFromTemplateFile(const std::string &appId, const std::string &pkgId, + const std::string &zoneId); void apply() const; void clear() const; @@ -59,8 +60,10 @@ public: * correct permissions to shared data. * * @param[in] pkgContents - a list of all applications inside this package + * @param[in] zoneId - ID of zone which requested application install */ - void generatePackageCrossDeps(const std::vector &pkgContents); + void generatePackageCrossDeps(const std::vector &pkgContents, + const std::string &zoneId); /** * Install package-specific smack rules. @@ -74,6 +77,20 @@ public: */ static void installApplicationRules(const std::string &appId, const std::string &pkgId, const std::vector &pkgContents); + + /** + * Install package-specific smack rules. + * + * Function creates smack rules using predefined template. Rules are applied + * to the kernel and saved on persistent storage so they are loaded on system boot. + * + * @param[in] appId - application id that is beeing installed + * @param[in] pkgId - package id that the application is in + * @param[in] pkgContents - a list of all applications in the package + * @param[in] zoneId - ID of zone which requested application install + */ + static void installApplicationRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents, const std::string &zoneId); /** * Uninstall package-specific smack rules. * @@ -97,9 +114,10 @@ public: * @param[in] appId - application id * @param[in] pkgId - package id that the application belongs to * @param[in] appsInPkg - a list of other applications in the same package id that the application belongs to + * @param[in] zoneId - ID of zone which requested application uninstall */ static void uninstallApplicationRules(const std::string &appId, const std::string &pkgId, - std::vector appsInPkg); + std::vector appsInPkg, const std::string &zoneId); /** * Update package specific rules @@ -110,8 +128,10 @@ public: * * @param[in] pkgId - id of the package to update * @param[in] pkgContents - a list of all applications in the package + * @param[in] zoneId - ID of zone which requested application uninstall */ - static void updatePackageRules(const std::string &pkgId, const std::vector &pkgContents); + static void updatePackageRules(const std::string &pkgId, + const std::vector &pkgContents, const std::string &zoneId); private: /** diff --git a/src/common/include/zone-utils.h b/src/common/include/zone-utils.h new file mode 100644 index 0000000..25caacc --- /dev/null +++ b/src/common/include/zone-utils.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000 - 2015 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 zone-utils.h + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief Definition of Zone utilities + */ + +#ifndef _SECURITY_MANAGER_ZONE_UTILS_H_ +#define _SECURITY_MANAGER_ZONE_UTILS_H_ + +#include + +// FIXME This module is a replacement for Vasum functions. +// +// When Vasum will be included into OBS, the module should be removed and vasum-client should +// be used instead. + +namespace SecurityManager +{ + +extern const std::string ZONE_HOST; + +/** + * Extracts Zone ID in which runs process having provided PID. + * + * This function parses /proc//cpuset file and tries to acquire Zone ID name from it. + * + * @param[in] pid PID of process to get Zone ID from. + * @param[out] zoneId Zone ID extracted from cpuset. If process runs in host, returns "host" string. + * @return True on success, false on failure. + */ +bool getZoneIdFromPid(int pid, std::string& zoneId); + +/** + * Generates zone-specific label from given @ref label and zone's name @ref zoneName + * + * @param[in] label Base label, used to generate new zone-specific label + * @param[in] zoneName Name of zone for which label will be generated + * @return Generated label + */ +std::string zoneSmackLabelGenerate(const std::string &label, const std::string &zoneName); + +/** + * Map @ref hostLabel to @ref zoneLabel using Smack namespaces. + * + * FIXME This is a placeholder for Vasum API - implement when Smack Namespaces are implemented + * + * @param[in] hostLabel Smack label as seen from hosts perspective + * @param[in] zoneName Zone ID to which label will be mapped + * @param[in] zoneLabel Smack label seen from zone's perspective + * @return True on success, false on failure + */ +bool zoneSmackLabelMap(const std::string &hostLabel, const std::string &zoneName, + const std::string &zoneLabel); + +/** + * Unmap label mapped by zoneSmackLabelMap. + * + * FIXME This is a placeholder for Vasum API - implement when Smack Namespaces are implemented + * + * @param[in] hostLabel Label to unmap + * @param[in] zoneName Zone ID for which unmapping should be done + * @return True on success, false on failure + */ +bool zoneSmackLabelUnmap(const std::string &hostLabel, const std::string &zoneName); + +} //namespace SecurityManager + +#endif //_SECURITY_MANAGER_ZONE_UTILS_H_ diff --git a/src/common/master-req.cpp b/src/common/master-req.cpp new file mode 100644 index 0000000..96555e3 --- /dev/null +++ b/src/common/master-req.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2015 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 master-req.cpp + * @author Lukasz Kostyra + * @brief Definitions of master request calls + */ + +#include "master-req.h" + +#include + +#include "message-buffer.h" +#include "connection.h" + +namespace SecurityManager { +namespace MasterReq { + +int CynaraPolicyUpdate(const std::string &appId, const std::string &uidstr, + const std::vector &oldPkgPrivileges, + const std::vector &newPkgPrivileges) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::CYNARA_UPDATE_POLICY)); + Serialization::Serialize(sendBuf, appId); + Serialization::Serialize(sendBuf, uidstr); + Serialization::Serialize(sendBuf, oldPkgPrivileges); + Serialization::Serialize(sendBuf, newPkgPrivileges); + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +int CynaraUserInit(const uid_t uidAdded, int userType) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::CYNARA_USER_INIT)); + Serialization::Serialize(sendBuf, uidAdded); + Serialization::Serialize(sendBuf, userType); + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +int CynaraUserRemove(const uid_t uidDeleted) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::CYNARA_USER_REMOVE)); + Serialization::Serialize(sendBuf, uidDeleted); + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +int SmackInstallRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::SMACK_INSTALL_RULES)); + Serialization::Serialize(sendBuf, appId); + Serialization::Serialize(sendBuf, pkgId); + Serialization::Serialize(sendBuf, pkgContents); + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +int SmackUninstallRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents, const bool removePkg) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::SMACK_UNINSTALL_RULES)); + Serialization::Serialize(sendBuf, appId); + Serialization::Serialize(sendBuf, pkgId); + Serialization::Serialize(sendBuf, pkgContents); + Serialization::Serialize(sendBuf, removePkg); + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +// Following three requests are just forwarded security-manager API calls +// these do not access Privilege DB, so all can be forwarded to Master +int PolicyUpdate(const std::vector &policyEntries, uid_t uid, pid_t pid, + const std::string &smackLabel) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::POLICY_UPDATE)); + Serialization::Serialize(sendBuf, policyEntries); + Serialization::Serialize(sendBuf, uid); + Serialization::Serialize(sendBuf, pid); + Serialization::Serialize(sendBuf, smackLabel); + + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, ret); + + return ret; +} + +int GetConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid, + const std::string &smackLabel, std::vector &policyEntries) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::GET_CONFIGURED_POLICY)); + Serialization::Serialize(sendBuf, forAdmin); + Serialization::Serialize(sendBuf, filter); + Serialization::Serialize(sendBuf, uid); + Serialization::Serialize(sendBuf, pid); + Serialization::Serialize(sendBuf, smackLabel); + + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) { + Deserialization::Deserialize(retBuf, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, policyEntries); + } + + return ret; +} + +int GetPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, + std::vector &policyEntries) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::GET_POLICY)); + Serialization::Serialize(sendBuf, filter); + Serialization::Serialize(sendBuf, uid); + Serialization::Serialize(sendBuf, pid); + Serialization::Serialize(sendBuf, smackLabel); + + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) { + Deserialization::Deserialize(retBuf, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, policyEntries); + } + + return ret; +} + +int PolicyGetDesc(std::vector &descriptions) +{ + int ret; + MessageBuffer sendBuf, retBuf; + Serialization::Serialize(sendBuf, + static_cast(MasterSecurityModuleCall::POLICY_GET_DESC)); + + ret = sendToServer(MASTER_SERVICE_SOCKET, sendBuf.Pop(), retBuf); + if (ret == SECURITY_MANAGER_API_SUCCESS) { + Deserialization::Deserialize(retBuf, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Deserialization::Deserialize(retBuf, descriptions); + } + + return ret; +} + +} // namespace MasterReq +} // namespace SecurityManager diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 20ee7a9..56d5e1c 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -41,8 +41,10 @@ #include "smack-rules.h" #include "smack-labels.h" #include "security-manager.h" +#include "zone-utils.h" #include "service_impl.h" +#include "master-req.h" namespace SecurityManager { namespace ServiceImpl { @@ -255,7 +257,23 @@ static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid, b return true; } -int appInstall(const app_inst_req &req, uid_t uid) +static inline bool getZoneId(std::string &zoneId) +{ + if (!getZoneIdFromPid(getpid(), zoneId)) { + LogError("Failed to get zone ID from current PID"); + return false; + } + + // This function should be called under slave mode only - assumes, that we work inside zone + if (zoneId == ZONE_HOST) { + LogError("We should not run in host - refusing request"); + return false; + } + + return true; +} + +int appInstall(const app_inst_req &req, uid_t uid, bool isSlave) { std::vector addedPermissions; std::vector removedPermissions; @@ -266,6 +284,14 @@ int appInstall(const app_inst_req &req, uid_t uid) std::string appLabel; std::string pkgLabel; + std::string zoneId; + if (isSlave) { + if (!getZoneId(zoneId)) { + LogError("Failed to get Zone ID."); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + if (uid) { if (uid != req.uid) { LogError("User " << uid << @@ -294,9 +320,9 @@ int appInstall(const app_inst_req &req, uid_t uid) try { std::vector oldAppPrivileges; - appLabel = SmackLabels::generateAppLabel(req.appId); + appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId); /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */ - pkgLabel = SmackLabels::generatePkgLabel(req.pkgId); + pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId); LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId << ", uidstr " << uidstr << ", app label: " << appLabel << ", pkg label: " << pkgLabel); @@ -314,8 +340,20 @@ int appInstall(const app_inst_req &req, uid_t uid) PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges); /* Get all application ids in the package to generate rules withing the package */ PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents); - CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges, - req.privileges); + + if (isSlave) { + int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges, + req.privileges); + if (ret != SECURITY_MANAGER_API_SUCCESS) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while processing request on master: " << ret); + return ret; + } + } else { + CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges, + req.privileges); + } + PrivilegeDb::getInstance().CommitTransaction(); LogDebug("Application installation commited to database"); } catch (const PrivilegeDb::Exception::IOError &e) { @@ -341,22 +379,35 @@ int appInstall(const app_inst_req &req, uid_t uid) try { if (isCorrectPath) - SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath); + SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId); // register paths for (const auto &appPath : req.appPaths) { const std::string &path = appPath.first; app_install_path_type pathType = static_cast(appPath.second); - SmackLabels::setupPath(req.appId, path, pathType); + SmackLabels::setupPath(req.appId, path, pathType, zoneId); } - LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: " - << req.pkgId << ". Applications in package: " << pkgContents.size()); - SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents); + if (isSlave) { + LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: " + << req.pkgId << ". Applications in package: " << pkgContents.size()); + int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents); + if (ret != SECURITY_MANAGER_API_SUCCESS) { + LogError("Master failed to apply package-specific smack rules: " << ret); + return ret; + } + } else { + LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: " + << req.pkgId << ". Applications in package: " << pkgContents.size()); + SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents); + } } catch (const SmackException::Base &e) { LogError("Error while applying Smack policy for application: " << e.DumpToString()); return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED; - } catch (const std::bad_alloc &e) { + } catch (const SecurityManager::Exception &e) { + LogError("Security Manager exception: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + }catch (const std::bad_alloc &e) { LogError("Memory allocation error: " << e.what()); return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; } @@ -364,7 +415,7 @@ int appInstall(const app_inst_req &req, uid_t uid) return SECURITY_MANAGER_API_SUCCESS; } -int appUninstall(const std::string &appId, uid_t uid) +int appUninstall(const std::string &appId, uid_t uid, bool isSlave) { std::string pkgId; std::string smackLabel; @@ -374,6 +425,14 @@ int appUninstall(const std::string &appId, uid_t uid) std::string uidstr; checkGlobalUser(uid, uidstr); + std::string zoneId; + if (isSlave) { + if (!getZoneId(zoneId)) { + LogError("Failed to get Zone ID."); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + try { std::vector oldAppPrivileges; @@ -384,7 +443,7 @@ int appUninstall(const std::string &appId, uid_t uid) PrivilegeDb::getInstance().RollbackTransaction(); appExists = false; } else { - smackLabel = SmackLabels::generateAppLabel(appId); + smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId); LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId << ", uidstr " << uidstr << ", generated smack label: " << smackLabel); @@ -395,8 +454,20 @@ int appUninstall(const std::string &appId, uid_t uid) PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges); PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector()); PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg); - CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges, - std::vector()); + + if (isSlave) { + int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges, + std::vector()); + if (ret != SECURITY_MANAGER_API_SUCCESS) { + PrivilegeDb::getInstance().RollbackTransaction(); + LogError("Error while processing request on master: " << ret); + return ret; + } + } else { + CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges, + std::vector()); + } + PrivilegeDb::getInstance().CommitTransaction(); LogDebug("Application uninstallation commited to database"); } @@ -421,22 +492,35 @@ int appUninstall(const std::string &appId, uid_t uid) return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; } - try { - if (appExists) { - if (removePkg) { - LogDebug("Removing Smack rules for deleted pkgId " << pkgId); - SmackRules::uninstallPackageRules(pkgId); - } + if (appExists) { + try { + if (isSlave) { + LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId << + " to master"); + int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg); + if (ret != SECURITY_MANAGER_API_SUCCESS) { + LogError("Error while processing uninstall request on master: " << ret); + return ret; + } + } else { + if (removePkg) { + LogDebug("Removing Smack rules for deleted pkgId " << pkgId); + SmackRules::uninstallPackageRules(pkgId); + } - LogDebug("Removing smack rules for deleted appId " << appId); - SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents); + LogDebug ("Removing smack rules for deleted appId " << appId); + SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId); + } + } catch (const SmackException::Base &e) { + LogError("Error while removing Smack rules for application: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED; + } catch (const SecurityManager::Exception &e) { + LogError("Security Manager error: " << e.DumpToString()); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation error: " << e.what()); + return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; } - } catch (const SmackException::Base &e) { - LogError("Error while removing Smack rules for application: " << e.DumpToString()); - return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED; - } catch (const std::bad_alloc &e) { - LogError("Memory allocation error: " << e.what()); - return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; } return SECURITY_MANAGER_API_SUCCESS; @@ -461,8 +545,18 @@ int getPkgId(const std::string &appId, std::string &pkgId) return SECURITY_MANAGER_API_SUCCESS; } -int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set &gids) +int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave, + std::unordered_set &gids) { + // FIXME Temporary solution, see below + std::string zoneId; + if (isSlave) { + if (!getZoneId(zoneId)) { + LogError("Failed to get Zone ID."); + return SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + } + } + try { std::string pkgId; std::string smackLabel; @@ -477,7 +571,9 @@ int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_ } LogDebug("pkgId: " << pkgId); - smackLabel = SmackLabels::generateAppLabel(appId); + // FIXME getAppGroups should work without generating zone-specific labels when + // Smack Namespaces will work + smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId); LogDebug("smack label: " << smackLabel); std::vector privileges; @@ -527,20 +623,30 @@ 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) +int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave) { if (uid != 0) return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED; - try { - CynaraAdmin::getInstance().UserInit(uidAdded, static_cast(userType)); - } catch (CynaraException::InvalidParam &e) { - return SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + if (isSlave) { + int ret = MasterReq::CynaraUserInit(uidAdded, + static_cast(userType)); + if (ret != SECURITY_MANAGER_API_SUCCESS) { + LogError("Master failed to initialize user " << uidAdded << " of type " << userType); + return ret; + } + } else { + try { + CynaraAdmin::getInstance().UserInit(uidAdded, static_cast(userType)); + } catch (CynaraException::InvalidParam &e) { + return SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + } } + return SECURITY_MANAGER_API_SUCCESS; } -int userDelete(uid_t uidDeleted, uid_t uid) +int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave) { int ret = SECURITY_MANAGER_API_SUCCESS; if (uid != 0) @@ -556,14 +662,22 @@ int userDelete(uid_t uidDeleted, uid_t uid) } for (auto &app: userApps) { - if (appUninstall(app, uidDeleted) != SECURITY_MANAGER_API_SUCCESS) { + if (appUninstall(app, uidDeleted, isSlave) != 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; } } - CynaraAdmin::getInstance().UserRemove(uidDeleted); + if (isSlave) { + int ret = MasterReq::CynaraUserRemove(uidDeleted); + if (ret) { + LogError("Master failed to delete user " << uidDeleted); + return ret; + } + } else { + CynaraAdmin::getInstance().UserRemove(uidDeleted); + } return ret; } diff --git a/src/common/smack-labels.cpp b/src/common/smack-labels.cpp index 0294a42..236d090 100644 --- a/src/common/smack-labels.cpp +++ b/src/common/smack-labels.cpp @@ -37,6 +37,7 @@ #include "security-manager.h" #include "smack-labels.h" +#include "zone-utils.h" namespace SecurityManager { namespace SmackLabels { @@ -125,8 +126,13 @@ static void labelDir(const std::string &path, const std::string &label, dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs); } -void setupPath(const std::string &appId, const std::string &path, - app_install_path_type pathType) +void setupPath(const std::string &appId, const std::string &path, app_install_path_type pathType) +{ + setupPath(appId, path, pathType, std::string()); +} + +void setupPath(const std::string &appId, const std::string &path, app_install_path_type pathType, + const std::string &zoneId) { std::string label; bool label_executables, label_transmute; @@ -134,7 +140,7 @@ void setupPath(const std::string &appId, const std::string &path, switch (pathType) { case SECURITY_MANAGER_PATH_PRIVATE: case SECURITY_MANAGER_PATH_RW: - label = generateAppLabel(appId); + label = zoneSmackLabelGenerate(generateAppLabel(appId), zoneId); label_executables = true; label_transmute = false; break; @@ -158,11 +164,17 @@ void setupPath(const std::string &appId, const std::string &path, void setupCorrectPath(const std::string &pkgId, const std::string &appId, const std::string &basePath) { + setupCorrectPath(pkgId, appId, basePath, std::string()); +} + +void setupCorrectPath(const std::string &pkgId, const std::string &appId, const std::string &basePath, + const std::string& zoneId) +{ std::string pkgPath = basePath + "/" + pkgId; std::string appPath = pkgPath + "/" + appId; - pathSetSmack(pkgPath.c_str(), generatePkgLabel(pkgId), XATTR_NAME_SMACK); - pathSetSmack(appPath.c_str(), generateAppLabel(appId), XATTR_NAME_SMACK); + pathSetSmack(pkgPath.c_str(), zoneSmackLabelGenerate(generatePkgLabel(pkgId), zoneId), XATTR_NAME_SMACK); + pathSetSmack(appPath.c_str(), zoneSmackLabelGenerate(generateAppLabel(appId), zoneId), XATTR_NAME_SMACK); pathSetSmack(appPath.c_str(), "TRUE", XATTR_NAME_SMACKTRANSMUTE); } diff --git a/src/common/smack-rules.cpp b/src/common/smack-rules.cpp index 3629e0f..d3bdf22 100644 --- a/src/common/smack-rules.cpp +++ b/src/common/smack-rules.cpp @@ -38,6 +38,7 @@ #include "smack-labels.h" #include "smack-rules.h" +#include "zone-utils.h" namespace SecurityManager { @@ -136,8 +137,8 @@ void SmackRules::saveToFile(const std::string &path) const } -void SmackRules::addFromTemplateFile(const std::string &appId, - const std::string &pkgId) +void SmackRules::addFromTemplateFile(const std::string &appId, const std::string &pkgId, + const std::string &zoneId) { std::vector templateRules; std::string line; @@ -157,11 +158,11 @@ void SmackRules::addFromTemplateFile(const std::string &appId, ThrowMsg(SmackException::FileError, "Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH); } - addFromTemplate(templateRules, appId, pkgId); + addFromTemplate(templateRules, appId, pkgId, zoneId); } void SmackRules::addFromTemplate(const std::vector &templateRules, - const std::string &appId, const std::string &pkgId) + const std::string &appId, const std::string &pkgId, const std::string &zoneId) { for (auto rule : templateRules) { if (rule.empty()) @@ -180,7 +181,7 @@ void SmackRules::addFromTemplate(const std::vector &templateRules, subject = SmackLabels::generateAppLabel(appId); if (subject == SMACK_PKG_LABEL_TEMPLATE) - subject = SmackLabels::generatePkgLabel(pkgId); + subject = SmackLabels::generatePkgLabel(pkgId); if (object == SMACK_APP_LABEL_TEMPLATE) object = SmackLabels::generateAppLabel(appId); @@ -188,11 +189,18 @@ void SmackRules::addFromTemplate(const std::vector &templateRules, if (object == SMACK_PKG_LABEL_TEMPLATE) object = SmackLabels::generatePkgLabel(pkgId); + if (!zoneId.empty()) { + // FIXME replace with vasum calls. See zone-utils.h + subject = zoneSmackLabelGenerate(subject, zoneId); + object = zoneSmackLabelGenerate(object, zoneId); + } + add(subject, object, permissions); } } -void SmackRules::generatePackageCrossDeps(const std::vector &pkgContents) +void SmackRules::generatePackageCrossDeps(const std::vector &pkgContents, + const std::string &zoneId) { LogDebug ("Generating cross-package rules"); @@ -204,8 +212,8 @@ void SmackRules::generatePackageCrossDeps(const std::vector &pkgCon if (object == subject) continue; - subjectLabel = SmackLabels::generateAppLabel(subject); - objectLabel = SmackLabels::generateAppLabel(object); + subjectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(subject), zoneId); + objectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(object), zoneId); LogDebug ("Trying to add rule subject: " << subjectLabel << " object: " << objectLabel << " perms: " << appsInPackagePerms); add(subjectLabel, objectLabel, appsInPackagePerms); } @@ -227,24 +235,31 @@ std::string SmackRules::getApplicationRulesFilePath(const std::string &appId) void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId, const std::vector &pkgContents) { + installApplicationRules(appId, pkgId, pkgContents, std::string()); +} + +void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId, + const std::vector &pkgContents, const std::string &zoneId) +{ SmackRules smackRules; std::string appPath = getApplicationRulesFilePath(appId); - smackRules.addFromTemplateFile(appId, pkgId); + smackRules.addFromTemplateFile(appId, pkgId, zoneId); if (smack_smackfs_path() != NULL) smackRules.apply(); smackRules.saveToFile(appPath); - updatePackageRules(pkgId, pkgContents); + updatePackageRules(pkgId, pkgContents, zoneId); } -void SmackRules::updatePackageRules(const std::string &pkgId, const std::vector &pkgContents) +void SmackRules::updatePackageRules(const std::string &pkgId, + const std::vector &pkgContents, const std::string &zoneId) { SmackRules smackRules; std::string pkgPath = getPackageRulesFilePath(pkgId); - smackRules.generatePackageCrossDeps(pkgContents); + smackRules.generatePackageCrossDeps(pkgContents, zoneId); if (smack_smackfs_path() != NULL) smackRules.apply(); @@ -258,10 +273,10 @@ void SmackRules::uninstallPackageRules(const std::string &pkgId) } void SmackRules::uninstallApplicationRules(const std::string &appId, - const std::string &pkgId, std::vector pkgContents) + const std::string &pkgId, std::vector pkgContents, const std::string &zoneId) { uninstallRules(getApplicationRulesFilePath(appId)); - updatePackageRules(pkgId, pkgContents); + updatePackageRules(pkgId, pkgContents, zoneId); } void SmackRules::uninstallRules(const std::string &path) diff --git a/src/common/zone-utils.cpp b/src/common/zone-utils.cpp new file mode 100644 index 0000000..95162c4 --- /dev/null +++ b/src/common/zone-utils.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2000 - 2015 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 zone-utils.cpp + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @version 1.0 + * @brief Implementation of Zone utility functions + */ + +#include "zone-utils.h" + +#include + +#include + +// FIXME This module is a replacement for Vasum functions. +// When Vasum will be included into OBS, the module should be replaced with vasum-client. + +namespace { + +const std::string CPUSET_HOST = "/"; +const std::string CPUSET_LXC_PREFIX = "/lxc/"; + +} // namespace + +namespace SecurityManager +{ + +// ZONE_HOST should be visible outside to other modules +const std::string ZONE_HOST = "host"; + +bool getZoneIdFromPid(int pid, std::string& zoneId) +{ + //open /proc//cpuset and get its contents + const std::string path = "/proc/" + std::to_string(pid) + "/cpuset"; + + std::ifstream cpusetFile(path); + if (!cpusetFile) { + LogError("Failed to open cpuset"); + return false; + } + + std::string cpuset; + std::getline(cpusetFile, cpuset); + cpusetFile.close(); + + //check if we are in host + if (cpuset == CPUSET_HOST) { + zoneId = ZONE_HOST; + return true; + } + + //in lxc container, cpuset contains "/lxc/" string - try to parse zoneID from there + //search for lxc prefix + size_t lxcPrefixPos = cpuset.find(CPUSET_LXC_PREFIX); + if (lxcPrefixPos == std::string::npos) { + LogError("LXC prefix not found - probably other virtualization method is used"); + return false; + } + + //assign zone name and leave + zoneId.assign(cpuset, CPUSET_LXC_PREFIX.size(), cpuset.size() - CPUSET_LXC_PREFIX.size()); + return true; +} + +std::string zoneSmackLabelGenerate(const std::string &label, const std::string &zoneName) +{ + if (zoneName.empty() || zoneName == ZONE_HOST) { + return label; + } + + return zoneName + "::" + label; +} + +bool zoneSmackLabelMap(const std::string &hostLabel, const std::string &zoneName, + const std::string &zoneLabel) +{ + (void) hostLabel; + (void) zoneName; + (void) zoneLabel; + // FIXME here Vasum should be called and Smack label mapping would commence + + return true; +} + +bool zoneSmackLabelUnmap(const std::string &hostLabel, const std::string &zoneName) +{ + (void) hostLabel; + (void) zoneName; + // FIXME here Vasum should be called and label shall be unmapped. + + return true; +} + +} // namespace SecurityManager diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 8890aa3..3c3be5d 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,6 +1,7 @@ PKG_CHECK_MODULES(SERVER_DEP REQUIRED libsystemd-daemon + cynara-client ) FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options) diff --git a/src/server/service/include/master-service.h b/src/server/service/include/master-service.h index 170bfd9..627cce9 100644 --- a/src/server/service/include/master-service.h +++ b/src/server/service/include/master-service.h @@ -54,6 +54,84 @@ private: * @return true on success */ bool processOne(const ConnectionID &conn, MessageBuffer &buffer, InterfaceID interfaceID); + + /** + * Process Cynara policy update during app installation/uninstallation + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + * @param zoneId ID of zone which requested the call + */ + void processCynaraUpdatePolicy(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId); + + /** + * Process Cynara user initialization + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + */ + void processCynaraUserInit(MessageBuffer &buffer, MessageBuffer &send); + + /** + * Process Cynara user removal + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + */ + void processCynaraUserRemove(MessageBuffer &buffer, MessageBuffer &send); + + /** + * Process policy update + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + */ + void processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send); + + /** + * Process configured policy acquisition + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + */ + void processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send); + + /** + * Process policy acquisition from Master + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + */ + // FIXME this function is not yet implemented. + void processGetPolicy(MessageBuffer &buffer, MessageBuffer &send); + + /** + * Process policy descriptions list acquisition + * + * @param send Raw data buffer to be sent + */ + void processPolicyGetDesc(MessageBuffer &send); + + /** + * Process SMACK rules installation for package. Map rules using Smack Namespaces. + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + * @param zoneId ID of zone which requested the call + */ + void processSmackInstallRules(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId); + + /** + * Process SMACK rules uninstallation + * + * @param buffer Raw received data buffer + * @param send Raw data buffer to be sent + * @param zoneId ID of zone which requested the call + */ + void processSmackUninstallRules(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId); }; } // namespace SecurityManager diff --git a/src/server/service/master-service.cpp b/src/server/service/master-service.cpp index 2afae00..f018abb 100644 --- a/src/server/service/master-service.cpp +++ b/src/server/service/master-service.cpp @@ -28,7 +28,11 @@ #include #include "protocols.h" +#include "zone-utils.h" +#include "cynara.h" #include "master-service.h" +#include "smack-rules.h" +#include "smack-labels.h" #include "service_impl.h" namespace SecurityManager { @@ -68,14 +72,66 @@ bool MasterService::processOne(const ConnectionID &conn, MessageBuffer &buffer, return false; } + // FIXME this part needs to be updated when Vasum is added to OBS. See zone-utils.h + std::string vsmZoneId; + if (!getZoneIdFromPid(pid, vsmZoneId)) { + LogError("Failed to extract Zone ID! Closing socket."); + m_serviceManager->Close(conn); + return false; + } + + if (vsmZoneId == ZONE_HOST) { + LogError("Connection came from host - in master mode this should not happen! Closing."); + m_serviceManager->Close(conn); + return false; + } + + LogInfo("Connection came from Zone " << vsmZoneId); + if (IFACE == interfaceID) { Try { // deserialize API call type int call_type_int; Deserialization::Deserialize(buffer, call_type_int); - SecurityModuleCall call_type = static_cast(call_type_int); + MasterSecurityModuleCall call_type = static_cast(call_type_int); switch (call_type) { + case MasterSecurityModuleCall::CYNARA_UPDATE_POLICY: + LogDebug("call type MasterSecurityModuleCall::CYNARA_UPDATE_POLICY"); + processCynaraUpdatePolicy(buffer, send, vsmZoneId); + break; + case MasterSecurityModuleCall::CYNARA_USER_INIT: + LogDebug("call type MasterSecurityModuleCall::CYNARA_USER_INIT"); + processCynaraUserInit(buffer, send); + break; + case MasterSecurityModuleCall::CYNARA_USER_REMOVE: + LogDebug("call type MasterSecurityModuleCall::CYNARA_USER_REMOVE"); + processCynaraUserRemove(buffer, send); + break; + case MasterSecurityModuleCall::POLICY_UPDATE: + LogDebug("call type MasterSecurityModuleCall::POLICY_UPDATE"); + processPolicyUpdate(buffer, send); + break; + case MasterSecurityModuleCall::GET_CONFIGURED_POLICY: + LogDebug("call type MasterSecurityModuleCall::GET_CONFIGURED_POLICY"); + processGetConfiguredPolicy(buffer, send); + break; + case MasterSecurityModuleCall::GET_POLICY: + LogDebug("call type MasterSecurityModuleCall::GET_POLICY"); + processGetPolicy(buffer, send); + break; + case MasterSecurityModuleCall::POLICY_GET_DESC: + LogDebug("call type MasterSecurityModuleCall::POLICY_GET_DESC"); + processPolicyGetDesc(send); + break; + case MasterSecurityModuleCall::SMACK_INSTALL_RULES: + LogDebug("call type MasterSecurityModuleCall::SMACK_INSTALL_RULES"); + processSmackInstallRules(buffer, send, vsmZoneId); + break; + case MasterSecurityModuleCall::SMACK_UNINSTALL_RULES: + LogDebug("call type MasterSecurityModuleCall::SMACK_UNINSTALL_RULES"); + processSmackUninstallRules(buffer, send, vsmZoneId); + break; default: LogError("Invalid call: " << call_type_int); Throw(MasterServiceException::InvalidAction); @@ -107,5 +163,252 @@ bool MasterService::processOne(const ConnectionID &conn, MessageBuffer &buffer, return retval; } +void MasterService::processCynaraUpdatePolicy(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + std::string appId; + std::string uidstr; + std::vector oldAppPrivileges, newAppPrivileges; + std::string appLabel, newLabel; + + Deserialization::Deserialize(buffer, appId); + Deserialization::Deserialize(buffer, uidstr); + Deserialization::Deserialize(buffer, oldAppPrivileges); + Deserialization::Deserialize(buffer, newAppPrivileges); + + appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId); + + try { + CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges, + newAppPrivileges); + } catch (const CynaraException::Base &e) { + LogError("Error while setting Cynara rules for application: " << e.DumpToString()); + goto out; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation while setting Cynara rules for application: " << e.what()); + ret = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = SECURITY_MANAGER_API_SUCCESS; + +out: + Serialization::Serialize(send, ret); +} + +void MasterService::processCynaraUserInit(MessageBuffer &buffer, MessageBuffer &send) +{ + int ret = SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + uid_t uidAdded; + int userType; + + Deserialization::Deserialize(buffer, uidAdded); + Deserialization::Deserialize(buffer, userType); + + try { + CynaraAdmin::getInstance().UserInit(uidAdded, + static_cast(userType)); + } catch (CynaraException::InvalidParam &e) { + goto out; + } + + ret = SECURITY_MANAGER_API_SUCCESS; +out: + Serialization::Serialize(send, ret); +} + +void MasterService::processCynaraUserRemove(MessageBuffer &buffer, MessageBuffer &send) +{ + int ret = SECURITY_MANAGER_API_ERROR_INPUT_PARAM; + uid_t uidDeleted; + + Deserialization::Deserialize(buffer, uidDeleted); + + try { + CynaraAdmin::getInstance().UserRemove(uidDeleted); + } catch (CynaraException::InvalidParam &e) { + goto out; + } + + ret = SECURITY_MANAGER_API_SUCCESS; +out: + Serialization::Serialize(send, ret); +} + +void MasterService::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + std::vector policyEntries; + uid_t uid; + pid_t pid; + std::string smackLabel; + + Deserialization::Deserialize(buffer, policyEntries); + Deserialization::Deserialize(buffer, uid); + Deserialization::Deserialize(buffer, pid); + Deserialization::Deserialize(buffer, smackLabel); + + ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel); + Serialization::Serialize(send, ret); +} + +void MasterService::processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + bool forAdmin; + policy_entry filter; + uid_t uid; + pid_t pid; + std::string smackLabel; + std::vector policyEntries; + + Deserialization::Deserialize(buffer, forAdmin); + Deserialization::Deserialize(buffer, filter); + Deserialization::Deserialize(buffer, uid); + Deserialization::Deserialize(buffer, pid); + Deserialization::Deserialize(buffer, smackLabel); + + ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries); + Serialization::Serialize(send, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Serialization::Serialize(send, policyEntries); +} + +void MasterService::processGetPolicy(MessageBuffer &buffer, MessageBuffer &send) +{ + (void) buffer; + int ret = SECURITY_MANAGER_API_ERROR_BAD_REQUEST; + + // FIXME getPolicy is not ready to work in Master mode. Uncomment below code when getPolicy will + // be implemented for Master. + /* + policy_entry filter; + uid_t uid; + pid_t pid; + std::string smackLabel; + std::vector policyEntries; + + Deserialization::Deserialize(buffer, filter); + Deserialization::Deserialize(buffer, uid); + Deserialization::Deserialize(buffer, pid); + Deserialization::Deserialize(buffer, smackLabel); + + ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries);*/ + Serialization::Serialize(send, ret); + /*if (ret == SECURITY_MANAGER_API_SUCCESS) + Serialization::Serialize(send, policyEntries);*/ +} + +void MasterService::processPolicyGetDesc(MessageBuffer &send) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + std::vector descriptions; + + ret = ServiceImpl::policyGetDesc(descriptions); + Serialization::Serialize(send, ret); + if (ret == SECURITY_MANAGER_API_SUCCESS) + Serialization::Serialize(send, descriptions); +} + +void MasterService::processSmackInstallRules(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + std::string appId, pkgId; + std::vector pkgContents; + + Deserialization::Deserialize(buffer, appId); + Deserialization::Deserialize(buffer, pkgId); + Deserialization::Deserialize(buffer, pkgContents); + + try { + LogDebug("Adding Smack rules for new appId: " << appId << " with pkgId: " + << pkgId << ". Applications in package: " << pkgContents.size()); + SmackRules::installApplicationRules(appId, pkgId, pkgContents, zoneId); + + // FIXME implement zoneSmackLabelMap and check if works when Smack Namespaces are implemented + std::string zoneAppLabel = SmackLabels::generateAppLabel(appId); + std::string zonePkgLabel = SmackLabels::generatePkgLabel(pkgId); + std::string hostAppLabel = zoneSmackLabelGenerate(zoneAppLabel, zoneId); + std::string hostPkgLabel = zoneSmackLabelGenerate(zonePkgLabel, zoneId); + + if (!zoneSmackLabelMap(hostAppLabel, zoneId, zoneAppLabel)) { + LogError("Failed to apply Smack label mapping for application " << appId); + goto out; + } + + if (!zoneSmackLabelMap(hostPkgLabel, zoneId, zonePkgLabel)) { + LogError("Failed to apply Smack label mapping for package " << pkgId); + goto out; + } + } catch (const SmackException::Base &e) { + LogError("Error while adding Smack rules for application: " << e.DumpToString()); + ret = SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED; + goto out; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation error: " << e.what()); + ret = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = SECURITY_MANAGER_API_SUCCESS; +out: + Serialization::Serialize(send, ret); +} + +void MasterService::processSmackUninstallRules(MessageBuffer &buffer, MessageBuffer &send, + const std::string &zoneId) +{ + int ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR; + std::string appId, pkgId; + std::vector pkgContents; + bool removePkg = false; + + Deserialization::Deserialize(buffer, appId); + Deserialization::Deserialize(buffer, pkgId); + Deserialization::Deserialize(buffer, pkgContents); + Deserialization::Deserialize(buffer, removePkg); + + try { + if (removePkg) { + LogDebug("Removing Smack rules for deleted pkgId " << pkgId); + SmackRules::uninstallPackageRules(pkgId); + } + + LogDebug ("Removing smack rules for deleted appId " << appId); + SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId); + + // FIXME implement zoneSmackLabelUnmap and check if works when Smack Namespaces are implemented + std::string zoneAppLabel = SmackLabels::generateAppLabel(appId); + std::string zonePkgLabel = SmackLabels::generatePkgLabel(pkgId); + std::string hostAppLabel = zoneSmackLabelGenerate(zoneAppLabel, zoneId); + std::string hostPkgLabel = zoneSmackLabelGenerate(zonePkgLabel, zoneId); + + if (!zoneSmackLabelUnmap(hostAppLabel, zoneId)) { + LogError("Failed to unmap Smack labels for application " << appId); + goto out; + } + + if (removePkg) { + if (!zoneSmackLabelUnmap(hostPkgLabel, zoneId)) { + LogError("Failed to unmap Smack label for package " << pkgId); + goto out; + } + } + } catch (const SmackException::Base &e) { + LogError("Error while removing Smack rules for application: " << e.DumpToString()); + ret = SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED; + goto out; + } catch (const std::bad_alloc &e) { + LogError("Memory allocation error: " << e.what()); + ret = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = SECURITY_MANAGER_API_SUCCESS; +out: + Serialization::Serialize(send, ret); +} } // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index 334ce19..a8ff402 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -33,6 +33,7 @@ #include "protocols.h" #include "service.h" #include "service_impl.h" +#include "master-req.h" namespace SecurityManager { @@ -193,7 +194,7 @@ void Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_ Deserialization::Deserialize(buffer, req.privileges); Deserialization::Deserialize(buffer, req.appPaths); Deserialization::Deserialize(buffer, req.uid); - Serialization::Serialize(send, ServiceImpl::appInstall(req, uid)); + Serialization::Serialize(send, ServiceImpl::appInstall(req, uid, m_isSlave)); } void Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid) @@ -201,7 +202,7 @@ void Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, ui std::string appId; Deserialization::Deserialize(buffer, appId); - Serialization::Serialize(send, ServiceImpl::appUninstall(appId, uid)); + Serialization::Serialize(send, ServiceImpl::appUninstall(appId, uid, m_isSlave)); } void Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send) @@ -224,7 +225,7 @@ void Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, ui int ret; Deserialization::Deserialize(buffer, appId); - ret = ServiceImpl::getAppGroups(appId, uid, pid, gids); + ret = ServiceImpl::getAppGroups(appId, uid, pid, m_isSlave, gids); Serialization::Serialize(send, ret); if (ret == SECURITY_MANAGER_API_SUCCESS) { Serialization::Serialize(send, static_cast(gids.size())); @@ -243,7 +244,7 @@ void Service::processUserAdd(MessageBuffer &buffer, MessageBuffer &send, uid_t u Deserialization::Deserialize(buffer, uidAdded); Deserialization::Deserialize(buffer, userType); - ret = ServiceImpl::userAdd(uidAdded, userType, uid); + ret = ServiceImpl::userAdd(uidAdded, userType, uid, m_isSlave); Serialization::Serialize(send, ret); } @@ -254,7 +255,7 @@ void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_ Deserialization::Deserialize(buffer, uidRemoved); - ret = ServiceImpl::userDelete(uidRemoved, uid); + ret = ServiceImpl::userDelete(uidRemoved, uid, m_isSlave); Serialization::Serialize(send, ret); } @@ -265,7 +266,11 @@ void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, ui Deserialization::Deserialize(buffer, policyEntries); - ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel); + if (m_isSlave) { + ret = MasterReq::PolicyUpdate(policyEntries, uid, pid, smackLabel); + } else { + ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel); + } Serialization::Serialize(send, ret); } @@ -275,7 +280,14 @@ void Service::processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &s policy_entry filter; Deserialization::Deserialize(buffer, filter); std::vector policyEntries; - ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries); + + if (m_isSlave) { + ret = MasterReq::GetConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries); + } else { + ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, + policyEntries); + } + Serialization::Serialize(send, ret); Serialization::Serialize(send, static_cast(policyEntries.size())); for (const auto &policyEntry : policyEntries) { @@ -289,7 +301,13 @@ void Service::processGetPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t policy_entry filter; Deserialization::Deserialize(buffer, filter); std::vector policyEntries; - ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries); + + if (m_isSlave) { + ret = MasterReq::GetPolicy(filter, uid, pid, smackLabel, policyEntries); + } else { + ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries); + } + Serialization::Serialize(send, ret); Serialization::Serialize(send, static_cast(policyEntries.size())); for (const auto &policyEntry : policyEntries) { @@ -302,7 +320,11 @@ void Service::processPolicyGetDesc(MessageBuffer &send) int ret; std::vector descriptions; - ret = ServiceImpl::policyGetDesc(descriptions); + if (m_isSlave) { + ret = MasterReq::PolicyGetDesc(descriptions); + } else { + ret = ServiceImpl::policyGetDesc(descriptions); + } Serialization::Serialize(send, ret); if (ret == SECURITY_MANAGER_API_SUCCESS) { Serialization::Serialize(send, static_cast(descriptions.size())); -- 2.7.4 From c59e060af988587ffe784ea0f9910c60862dadd0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Wed, 10 Jun 2015 15:03:48 +0200 Subject: [PATCH 11/16] Add missing dependency to tzplatform MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Change-Id: Ifdf742b820a4cf7b76ef1dc6f8c831a24bfb55ef Signed-off-by: José Bollo --- src/cmd/CMakeLists.txt | 6 ++++++ src/server/CMakeLists.txt | 1 + 2 files changed, 7 insertions(+) diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt index ee9a160..70556c6 100644 --- a/src/cmd/CMakeLists.txt +++ b/src/cmd/CMakeLists.txt @@ -1,3 +1,8 @@ +PKG_CHECK_MODULES(CMD_DEP + REQUIRED + libtzplatform-config + ) + FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options) INCLUDE_DIRECTORIES(SYSTEM @@ -24,6 +29,7 @@ SET_TARGET_PROPERTIES(${TARGET_CMD} TARGET_LINK_LIBRARIES(${TARGET_CMD} ${TARGET_COMMON} ${TARGET_CLIENT} + ${CMD_DEP_LIBRARIES} ${Boost_LIBRARIES} ) diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 3c3be5d..b4efd53 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,6 +1,7 @@ PKG_CHECK_MODULES(SERVER_DEP REQUIRED libsystemd-daemon + libtzplatform-config cynara-client ) -- 2.7.4 From 28af75afb794b057804808589b3f5526c39c5f87 Mon Sep 17 00:00:00 2001 From: "jooseong.lee" Date: Thu, 18 Jun 2015 14:37:04 +0900 Subject: [PATCH 12/16] Add 'sed' dependency to fix a image creation error Change-Id: I2a20f7cdd16e3b4d18fb8497c0e51f66604d1935 Signed-off-by: jooseong.lee --- packaging/security-manager.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 8baa231..f11260c 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -48,6 +48,7 @@ Development files needed for using the security manager client %package policy Summary: Security manager policy Group: Security/Access Control +Requires: sed Requires(post): security-manager = %{version}-%{release} Requires(post): cyad Requires(post): sqlite -- 2.7.4 From 075ceae2887cc445d76a08a12a93290deb16f9fe Mon Sep 17 00:00:00 2001 From: jooseong Date: Mon, 3 Aug 2015 20:03:16 +0900 Subject: [PATCH 13/16] Add lock permission to 'System::Shared' label in app-rules-template.smack Change-Id: I168785779c19a9d79c8baf96b188934db9beb019 --- policy/app-rules-template.smack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/app-rules-template.smack b/policy/app-rules-template.smack index 1311169..d0b6fb2 100644 --- a/policy/app-rules-template.smack +++ b/policy/app-rules-template.smack @@ -1,6 +1,6 @@ System ~APP~ rwx ~APP~ System wx -~APP~ System::Shared rx +~APP~ System::Shared rxl ~APP~ System::Run rwxat ~APP~ System::Log rwxa ~APP~ _ l -- 2.7.4 From 6f3af61675fc43c8f2c12a8b007274ad5997bec9 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Mon, 6 Jul 2015 17:38:30 +0200 Subject: [PATCH 14/16] Add API for privilege mapping between versions Change-Id: Id61c2e4d8ff0252f6269ba3c6756170bdca38295 --- src/client/client-security-manager.cpp | 22 ++++++++++++++++++++++ src/include/security-manager.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/client/client-security-manager.cpp b/src/client/client-security-manager.cpp index 5a8c4d8..48b4594 100644 --- a/src/client/client-security-manager.cpp +++ b/src/client/client-security-manager.cpp @@ -978,3 +978,25 @@ void security_manager_policy_levels_free(char **levels, size_t levels_count) delete[] levels; } + +SECURITY_MANAGER_API +int security_manager_get_privileges_mapping(const char *from_version, + const char *to_version, + char const * const *privileges, + size_t privileges_count, + char ***privileges_mappings, + size_t *mappings_count) +{ + (void)to_version; + if (from_version == nullptr || privileges == nullptr || + privileges_mappings == nullptr || mappings_count == nullptr || privileges_count == 0) { + return SECURITY_MANAGER_ERROR_INPUT_PARAM; + } + return SECURITY_MANAGER_ERROR_UNKNOWN; +} +SECURITY_MANAGER_API +void security_manager_privilege_mapping_free(char **privileges_mappings, size_t mappings_count) +{ + (void)privileges_mappings; + (void)mappings_count; +} diff --git a/src/include/security-manager.h b/src/include/security-manager.h index 9ddcfca..a96d5e7 100644 --- a/src/include/security-manager.h +++ b/src/include/security-manager.h @@ -731,6 +731,35 @@ int security_manager_policy_levels_get(char ***levels, size_t *levels_count); */ void security_manager_policy_levels_free(char **levels, size_t levels_count); +/** + * This function returns mapping of MULTIPLE privileges from one version to the other. + * List of privileges is a union of mappings of every single given privilege. + * + * Caller needs to free memory allocated for the list using + * security_manager_privilege_mapping_free(). + * + * @param[in] from_version Version of passed privilege + * @param[in] to_version Version of requested mapping, if NULL default one will be used + * @param[in] privileges Names of privileges to be mapped + * @param[in] privileges_count Number of privileges to be mapped + * @param[out] privilege_mapping Pointer to list of sum of privileges which given privileges maps to + * @param[out] mapping_count + * @return API return code or error code + */ +int security_manager_get_privileges_mapping(const char *from_version, + const char *to_version, + char const * const *privileges, + size_t privileges_count, + char ***privileges_mappings, + size_t *mappings_count); +/** + * This function frees memory allocated by security_manager_get_privilege_mapping() and + * security_manager_get_privileges_mapping(). + * + * @param[in] privilege_mapping List of privileges + * @param[in] mapping_count Number of privileges + */ +void security_manager_privilege_mapping_free(char **privileges_mappings, size_t mappings_count); #ifdef __cplusplus } #endif -- 2.7.4 From 164926aa1855366d4efc7b0884654107c00cca7c Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Mon, 6 Jul 2015 17:38:44 +0200 Subject: [PATCH 15/16] Prepare db for privilege mapping Change-Id: I21d85830d97c250048c1c24b777897d2a9da5d13 --- db/db.sql | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/db/db.sql b/db/db.sql index fd3e084..a95238b 100644 --- a/db/db.sql +++ b/db/db.sql @@ -23,7 +23,13 @@ FOREIGN KEY (pkg_id) REFERENCES pkg (pkg_id) CREATE TABLE IF NOT EXISTS privilege ( privilege_id INTEGER PRIMARY KEY, -name VARCHAR NOT NULL , +name VARCHAR NOT NULL, +UNIQUE (name) +); + +CREATE TABLE IF NOT EXISTS version ( +version_id INTEGER PRIMARY KEY, +name VARCHAR NOT NULL, UNIQUE (name) ); @@ -42,6 +48,32 @@ PRIMARY KEY (privilege_id, group_name), FOREIGN KEY (privilege_id) REFERENCES privilege (privilege_id) ); +CREATE TABLE IF NOT EXISTS privilege_mapping ( +version_from_id INTEGER NOT NULL, +privilege_id INTEGER NOT NULL, +version_to_id INTEGER NOT NULL, +privilege_mapping_id INTEGER NOT NULL, +PRIMARY KEY (version_from_id, privilege_id, version_to_id, privilege_mapping_id), +FOREIGN KEY (privilege_id) REFERENCES privilege (privilege_id) +FOREIGN KEY (version_from_id) REFERENCES version (version_id) +FOREIGN KEY (privilege_mapping_id) REFERENCES privilege (privilege_id) +FOREIGN KEY (version_to_id) REFERENCES version (version_id) +); + +CREATE TABLE IF NOT EXISTS privilege_default_mapping ( +version_from_id INTEGER NOT NULL, +version_to_id INTEGER NOT NULL, +privilege_mapping_id INTEGER NOT NULL, +PRIMARY KEY (version_from_id, version_to_id, privilege_mapping_id), +FOREIGN KEY (version_from_id) REFERENCES version (version_id) +FOREIGN KEY (privilege_mapping_id) REFERENCES privilege (privilege_id) +FOREIGN KEY (version_to_id) REFERENCES version (version_id) +); + +CREATE TABLE IF NOT EXISTS privilege_to_map ( +privilege_name VARCHAR +); + DROP VIEW IF EXISTS app_privilege_view; CREATE VIEW app_privilege_view AS SELECT @@ -118,4 +150,56 @@ BEGIN INSERT OR IGNORE INTO privilege_group(privilege_id, group_name) VALUES ((SELECT privilege_id FROM privilege WHERE name=NEW.privilege_name), NEW.group_name); END; +DROP VIEW IF EXISTS privilege_mapping_view; +CREATE VIEW privilege_mapping_view AS +SELECT + version1.name AS version_from_name, + version2.name AS version_to_name, + privilege1.name AS privilege_name, + privilege2.name AS privilege_mapping_name +FROM privilege_mapping +LEFT JOIN privilege AS privilege1 ON privilege_mapping.privilege_id = privilege1.privilege_id +LEFT JOIN privilege AS privilege2 ON privilege_mapping.privilege_mapping_id = privilege2.privilege_id +LEFT JOIN version AS version1 ON privilege_mapping.version_from_id = version1.version_id +LEFT JOIN version AS version2 ON privilege_mapping.version_to_id = version2.version_id +UNION +SELECT + version1.name AS version_from_name, + version2.name AS version_to_name, + NULL AS privilege_name, + privilege2.name AS privilege_mapping_name +FROM privilege_default_mapping +LEFT JOIN privilege AS privilege2 ON privilege_default_mapping.privilege_mapping_id = privilege2.privilege_id +LEFT JOIN version AS version1 ON privilege_default_mapping.version_from_id = version1.version_id +LEFT JOIN version AS version2 ON privilege_default_mapping.version_to_id = version2.version_id; + +DROP TRIGGER IF EXISTS privilege_mapping_insert_trigger; +CREATE TRIGGER privilege_mapping_insert_trigger +INSTEAD OF INSERT ON privilege_mapping_view +WHEN (NEW.privilege_name IS NOT NULL) +BEGIN + INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_name); + INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_mapping_name); + INSERT OR IGNORE INTO version(name) VALUES (NEW.version_from_name); + INSERT OR IGNORE INTO version(name) VALUES (NEW.version_to_name); + INSERT OR IGNORE INTO privilege_mapping(privilege_id, version_from_id, privilege_mapping_id, version_to_id) VALUES + ((SELECT privilege_id FROM privilege WHERE name=NEW.privilege_name), + (SELECT version_id FROM version WHERE name=NEW.version_from_name), + (SELECT privilege_id FROM privilege WHERE name=NEW.privilege_mapping_name), + (SELECT version_id FROM version WHERE name=NEW.version_to_name)); +END; + +DROP TRIGGER IF EXISTS privilege_default_mapping_insert_trigger; +CREATE TRIGGER privilege_default_mapping_insert_trigger +INSTEAD OF INSERT ON privilege_mapping_view +WHEN (NEW.privilege_name IS NULL) +BEGIN + INSERT OR IGNORE INTO privilege(name) VALUES (NEW.privilege_mapping_name); + INSERT OR IGNORE INTO version(name) VALUES (NEW.version_from_name); + INSERT OR IGNORE INTO version(name) VALUES (NEW.version_to_name); + INSERT OR IGNORE INTO privilege_default_mapping(version_from_id, privilege_mapping_id, version_to_id) VALUES + ((SELECT version_id FROM version WHERE name=NEW.version_from_name), + (SELECT privilege_id FROM privilege WHERE name=NEW.privilege_mapping_name), + (SELECT version_id FROM version WHERE name=NEW.version_to_name)); +END; COMMIT TRANSACTION; -- 2.7.4 From 53495035be7c2fafd7885b93f60018bc5a39d818 Mon Sep 17 00:00:00 2001 From: Zofia Abramowska Date: Tue, 7 Jul 2015 14:57:07 +0200 Subject: [PATCH 16/16] Support std::string in SqlConnection binding Change-Id: I24bc608cfece4849639fcf529148cfdcf4af27a7 --- src/dpl/db/include/dpl/db/sql_connection.h | 8 ++++++++ src/dpl/db/src/sql_connection.cpp | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/dpl/db/include/dpl/db/sql_connection.h b/src/dpl/db/include/dpl/db/sql_connection.h index 510bacb..185af59 100644 --- a/src/dpl/db/include/dpl/db/sql_connection.h +++ b/src/dpl/db/include/dpl/db/sql_connection.h @@ -159,6 +159,14 @@ class SqlConnection void BindString(ArgumentIndex position, const String& value); /** + * Bind string to the prepared statement argument + * + * @param position Index of argument to bind value to + * @param value Value to bind + */ + void BindString(ArgumentIndex position, const std::string& value); + + /** * Bind optional int to the prepared statement argument. * If optional is not set null will be bound * diff --git a/src/dpl/db/src/sql_connection.cpp b/src/dpl/db/src/sql_connection.cpp index fdb4fe4..ccea00b 100644 --- a/src/dpl/db/src/sql_connection.cpp +++ b/src/dpl/db/src/sql_connection.cpp @@ -232,6 +232,18 @@ void SqlConnection::DataCommand::BindString( BindString(position, ToUTF8String(value).c_str()); } +void SqlConnection::DataCommand::BindString( + SqlConnection::ArgumentIndex position, + const std::string& value) +{ + CheckBindResult(sqlite3_bind_text(m_stmt, position, + value.c_str(), value.length(), + SQLITE_TRANSIENT)); + + LogPedantic("SQL data command bind string: [" + << position << "] -> " << value); +} + void SqlConnection::DataCommand::BindInteger( SqlConnection::ArgumentIndex position, const boost::optional &value) -- 2.7.4