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
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}
%{_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}
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
{
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
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
#include <grp.h>
#include <limits.h>
#include <pwd.h>
+#include <sys/socket.h>
#include <cstring>
#include <algorithm>
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;
libsystemd-daemon
)
-FIND_PACKAGE(Boost REQUIRED)
+FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options)
FIND_PACKAGE(Threads REQUIRED)
INCLUDE_DIRECTORIES(SYSTEM
${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})
${TARGET_COMMON}
${CMAKE_THREAD_LIBS_INIT}
${SERVER_DEP_LIBRARIES}
+ ${Boost_LIBRARIES}
)
INSTALL(TARGETS ${TARGET_SERVER} DESTINATION ${BIN_INSTALL_DIR})
#include <dpl/singleton.h>
#include <dpl/singleton_safe_impl.h>
+#include <boost/program_options.hpp>
+#include <iostream>
+
#include <socket-manager.h>
#include <file-lock.h>
#include <service.h>
+#include <master-service.h>
+
+namespace po = boost::program_options;
IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem);
-#define REGISTER_SOCKET_SERVICE(manager, service) \
- registerSocketService<service>(manager, #service)
+#define REGISTER_SOCKET_SERVICE(manager, service, allocator) \
+ registerSocketService<service>(manager, #service, allocator)
template<typename T>
-bool registerSocketService(SecurityManager::SocketManager &manager, const std::string& serviceName)
+bool registerSocketService(SecurityManager::SocketManager &manager,
+ const std::string& serviceName,
+ const std::function<T*(void)>& serviceAllocator)
{
T *service = NULL;
try {
- service = new T();
+ service = serviceAllocator();
service->Create();
manager.RegisterSocketService(service);
return true;
return false;
}
-int main(void) {
-
+int main(int argc, char* argv[])
+{
UNHANDLED_EXCEPTION_HANDLER_BEGIN
{
+ // initialize logging
SecurityManager::Singleton<SecurityManager::Log::LogSystem>::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<char> parsed =
+ po::command_line_parser(argc, argv).options(optDesc).allow_unregistered().run();
+
+ std::vector<std::string> 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);
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();
return EXIT_FAILURE;
}
UNHANDLED_EXCEPTION_HANDLER_END
- return 0;
+ return EXIT_SUCCESS;
}
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ * 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 <l.kostyra@samsung.com>
+ * @author Rafal Krypa <r.krypa@samsung.com>
+ * @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_
public SecurityManager::BaseService
{
public:
- Service();
+ Service(const bool isSlave);
ServiceDescriptionVector GetServiceDescription();
private:
+ const bool m_isSlave;
+
/**
* Handle request from a client
*
--- /dev/null
+/*
+ * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Rafal Krypa <r.krypa@samsung.com>
+ *
+ * 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 <l.kostyra@samsung.com>
+ * @author Rafal Krypa <r.krypa@samsung.com>
+ * @brief Implementation of security-manager master service.
+ */
+
+#include <generic-socket-manager.h>
+
+#include <dpl/log/log.h>
+#include <dpl/serialization.h>
+
+#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<SecurityModuleCall>(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
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)
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}
)
--- /dev/null
+[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
--- /dev/null
+[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
--- /dev/null
+[Unit]
+Description=Start the security manager slave
+ConditionVirtualization=lxc
+
+[Service]
+Type=notify
+ExecStart=@BIN_INSTALL_DIR@/security-manager --slave
+
+Sockets=security-manager-slave.socket
--- /dev/null
+[Socket]
+ListenStream=/run/security-manager-slave.socket
+Symlinks=/run/security-manager.socket
+SocketMode=0777
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+Service=security-manager-slave.service
+
+[Unit]
+ConditionVirtualization=lxc
[Unit]
Description=Start the security manager
+ConditionVirtualization=!lxc
+ConditionPathExists=!/usr/share/.zones/enabled
[Service]
Type=notify
# TODO: move to separate systemd service
Service=security-manager.service
+[Unit]
+ConditionVirtualization=!lxc
+ConditionPathExists=!/usr/share/.zones/enabled
+
[Install]
WantedBy=sockets.target