Implement installer service
authorMichal Witanowski <m.witanowski@samsung.com>
Tue, 4 Mar 2014 08:40:00 +0000 (09:40 +0100)
committerMichal Witanowski <m.witanowski@samsung.com>
Thu, 8 May 2014 09:26:19 +0000 (11:26 +0200)
[Bug/Feature]  Create new Security Server's service interfacing
               with libprivilege-control API.
[Cause]        N/A
[Solution]     Create PrivilegeControlSevice and implement protocol
               supporting libprivilege-control's API used by
               installers.
[Verification] Build and install Security Server.

Change-Id: I95a0e9a7cb69952e8f3b71665fcd7d9867939759
Signed-off-by: Michal Witanowski <m.witanowski@samsung.com>
packaging/security-server.spec
src/CMakeLists.txt
src/server/common/protocols.h
src/server/main/server2-main.cpp
src/server/service/installer.cpp [new file with mode: 0644]
src/server/service/installer.h [new file with mode: 0644]
systemd/CMakeLists.txt
systemd/security-manager-installer.socket [new file with mode: 0644]
systemd/security-server.service

index f12cd1d..6a08810 100644 (file)
@@ -117,6 +117,7 @@ ln -s ../security-server-app-privilege-by-name.socket %{buildroot}/usr/lib/syste
 ln -s ../security-server-password-check.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-password-check.socket
 ln -s ../security-server-password-set.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-password-set.socket
 ln -s ../security-server-password-reset.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-password-reset.socket
+ln -s ../security-manager-installer.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-manager-installer.socket
 
 %clean
 rm -rf %{buildroot}
@@ -180,6 +181,8 @@ fi
 %attr(-,root,root) /usr/lib/systemd/system/security-server-password-set.socket
 %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-password-reset.socket
 %attr(-,root,root) /usr/lib/systemd/system/security-server-password-reset.socket
+%attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-manager-installer.socket
+%attr(-,root,root) /usr/lib/systemd/system/security-manager-installer.socket
 
 %{_datadir}/license/%{name}
 
index 9c08d76..b4ea4ea 100644 (file)
@@ -26,6 +26,7 @@ SET(SECURITY_SERVER_SOURCES
     ${SERVER2_PATH}/service/password-manager.cpp
     ${SERVER2_PATH}/service/password-file-buffer.cpp
     ${SERVER2_PATH}/service/smack-common.cpp
+    ${SERVER2_PATH}/service/installer.cpp
     )
 
 SET_SOURCE_FILES_PROPERTIES(
index 9f6f9cc..3d17dca 100644 (file)
@@ -95,4 +95,3 @@ extern const int SECURITY_SERVER_MAX_OBJ_NAME;
 } // namespace SecuritySever
 
 #endif // _SECURITY_SERVER_PROTOCOLS_
-
index e1e7d20..26fff65 100644 (file)
@@ -36,6 +36,7 @@
 #include <privilege-by-pid.h>
 #include <cookie.h>
 #include <password.h>
+#include <installer.h>
 
 IMPLEMENT_SAFE_SINGLETON(SecurityServer::Log::LogSystem);
 
@@ -97,10 +98,10 @@ int main(void) {
         REGISTER_SOCKET_SERVICE(manager, SecurityServer::GetGidService);
         REGISTER_SOCKET_SERVICE(manager, SecurityServer::PrivilegeByPidService);
         REGISTER_SOCKET_SERVICE(manager, SecurityServer::PasswordService);
+        REGISTER_SOCKET_SERVICE(manager, SecurityServer::InstallerService);
 
         manager.MainLoop();
     }
     UNHANDLED_EXCEPTION_HANDLER_END
     return 0;
 }
-
diff --git a/src/server/service/installer.cpp b/src/server/service/installer.cpp
new file mode 100644 (file)
index 0000000..16b270c
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bartlomiej Grzelewski <b.grzelewski@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        installer.cpp
+ * @author      Michal Witanowski (m.witanowski@samsung.com)
+ * @brief       Implementation of installer service for libprivilege-control encapsulation.
+ */
+
+#include <dpl/log/log.h>
+#include <dpl/serialization.h>
+
+#include <privilege-control.h>
+#include "installer.h"
+#include "protocols.h"
+#include "security-server.h"
+#include "security-manager.h"
+
+namespace SecurityServer {
+
+namespace {
+
+const InterfaceID INSTALLER_IFACE = 0;
+
+/**
+ * Convert Security Mangager's API path type to libprivilege-control's API path type.
+ * @return true on success
+ */
+bool TranslateAppPathType(const app_install_path_type path_type,
+                          app_path_type_t& lpc_path_type)
+{
+    switch (path_type) {
+        case SECURITY_MANAGER_PATH_PRIVATE:
+            lpc_path_type = APP_PATH_PRIVATE;
+            break;
+        case SECURITY_MANAGER_PATH_PUBLIC:
+            lpc_path_type = APP_PATH_PUBLIC;
+            break;
+        case SECURITY_MANAGER_PATH_PUBLIC_RO:
+            lpc_path_type = APP_PATH_FLOOR;
+            break;
+        default:
+            return false;
+    };
+    return true;
+}
+
+} // namespace anonymous
+
+
+InstallerService::InstallerService()
+{
+}
+
+GenericSocketService::ServiceDescriptionVector InstallerService::GetServiceDescription()
+{
+    return ServiceDescriptionVector {
+        {SERVICE_SOCKET_INSTALLER, "security-server::installer", INSTALLER_IFACE},
+    };
+}
+
+void InstallerService::accept(const AcceptEvent &event)
+{
+    LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock <<
+             " ConnectionID.counter: " << event.connectionID.counter <<
+             " ServiceID: " << event.interfaceID);
+
+    auto &info = m_connectionInfoMap[event.connectionID.counter];
+    info.interfaceID = event.interfaceID;
+}
+
+void InstallerService::write(const WriteEvent &event)
+{
+    LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
+             " Size: " << event.size <<
+             " Left: " << event.left);
+
+    if (event.left == 0)
+        m_serviceManager->Close(event.connectionID);
+}
+
+void InstallerService::process(const ReadEvent &event)
+{
+    LogDebug("Read event for counter: " << event.connectionID.counter);
+    auto &info = m_connectionInfoMap[event.connectionID.counter];
+    info.buffer.Push(event.rawBuffer);
+
+    // We can get several requests in one package.
+    // Extract and process them all
+    while (processOne(event.connectionID, info.buffer, info.interfaceID));
+}
+
+void InstallerService::close(const CloseEvent &event)
+{
+    LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
+    m_connectionInfoMap.erase(event.connectionID.counter);
+}
+
+bool InstallerService::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;
+
+    if (INSTALLER_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) {
+                case SecurityModuleCall::APP_INSTALL:
+                    processAppInstall(buffer, send);
+                    break;
+                case SecurityModuleCall::APP_UNINSTALL:
+                    processAppUninstall(buffer, send);
+                    break;
+                default:
+                    LogError("Invalid call: " << call_type_int);
+                    Throw(InstallerException::InvalidAction);
+            }
+            // if we reach this point, the protocol is OK
+            retval = true;
+        } Catch (MessageBuffer::Exception::Base) {
+            LogError("Broken protocol.");
+        } Catch (InstallerException::Base) {
+            LogError("Broken protocol.");
+        } catch (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;
+}
+
+bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &send)
+{
+    // deserialize request data
+    app_inst_req req;
+    Deserialization::Deserialize(buffer, req.appId);
+    Deserialization::Deserialize(buffer, req.pkgId);
+    Deserialization::Deserialize(buffer, req.allowedUsers);
+    Deserialization::Deserialize(buffer, req.privileges);
+    Deserialization::Deserialize(buffer, req.appPaths);
+
+    LogDebug("appId: " << req.appId);
+    LogDebug("pkgId: " << req.pkgId);
+
+    // create null terminated array of strigns for permissions
+    std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
+    for (size_t i = 0; i < req.privileges.size(); ++i) {
+        LogDebug("Permission = " << req.privileges[i]);
+        pp_permissions[i] = req.privileges[i].c_str();
+    }
+    pp_permissions[req.privileges.size()] = nullptr;
+
+    // start database transaction
+    int result = perm_begin();
+    LogDebug("perm_begin() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // libprivilege is locked
+        Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+        return false;
+    }
+
+    /**
+     * TODO: use pkgId.
+     * This is a temporary solution: perm_app_* requires pkgId. We assume that pkgId == appId.
+     */
+    result = perm_app_install(req.appId.c_str());
+    LogDebug("perm_app_install() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // libprivilege error
+        goto error_label;
+    }
+
+    // TODO: use pkgId.
+    result = perm_app_enable_permissions(req.appId.c_str(), APP_TYPE_WGT,
+                                         pp_permissions.get(), true);
+    LogDebug("perm_app_enable_permissions() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // libprivilege error
+        goto error_label;
+    }
+
+    // register paths
+    for (const auto& appPath : req.appPaths) {
+        app_path_type_t path_type;
+        if (!TranslateAppPathType((app_install_path_type)appPath.second,
+                                  path_type)) {
+            LogError("Unrecognized path type: " << appPath.second);
+            goto error_label;
+        }
+        LogDebug("Adding path: " << appPath.first << " (type " << path_type << ")");
+
+        // TODO: use pkgId.
+        result = perm_app_setup_path(req.appId.c_str(), appPath.first.c_str(), path_type);
+        if (PC_OPERATION_SUCCESS != result) {
+            // libprivilege error
+            LogDebug("perm_app_setup_path() returned " << result);
+            goto error_label;
+        }
+    }
+
+    // finish database transaction
+    result = perm_end();
+    LogDebug("perm_end() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // error in libprivilege-control
+        Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+        return false;
+    }
+
+    // success
+    Serialization::Serialize(send, SECURITY_SERVER_API_SUCCESS);
+    return true;
+
+error_label:
+    // rollback failed transaction before exiting
+    result = perm_rollback();
+    LogDebug("perm_rollback() returned " << result);
+    Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+    return false;
+}
+
+bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send)
+{
+    // deserialize request data
+    std::string appId;
+    Deserialization::Deserialize(buffer, appId);
+    LogDebug("appId: " << appId);
+
+    int result = perm_begin();
+    LogDebug("perm_begin() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // libprivilege is locked
+        Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+        return false;
+    }
+
+    // TODO: use pkgId.
+    result = perm_app_uninstall(appId.c_str());
+    LogDebug("perm_app_uninstall() returned " << result);
+
+    if (PC_OPERATION_SUCCESS != result) {
+        // error in libprivilege-control
+        result = perm_rollback();
+        LogDebug("perm_rollback() returned " << result);
+        Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+        return false;
+    }
+
+    // finish database transaction
+    result = perm_end();
+    LogDebug("perm_end() returned " << result);
+    if (PC_OPERATION_SUCCESS != result) {
+        // error in libprivilege-control
+        Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR);
+        return false;
+    }
+
+    // success
+    Serialization::Serialize(send, SECURITY_SERVER_API_SUCCESS);
+    return true;
+}
+
+} // namespace SecurityServer
diff --git a/src/server/service/installer.h b/src/server/service/installer.h
new file mode 100644 (file)
index 0000000..843dca8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bartlomiej Grzelewski <b.grzelewski@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        installer.h
+ * @author      Michal Witanowski (m.witanowski@samsung.com)
+ * @brief       Implementation of installer service for libprivilege-control encapsulation.
+ */
+
+#ifndef _SECURITY_SERVER_INSTALLER_
+#define _SECURITY_SERVER_INSTALLER_
+
+#include <service-thread.h>
+#include <generic-socket-manager.h>
+#include <message-buffer.h>
+#include <connection-info.h>
+
+namespace SecurityServer {
+
+class InstallerException
+{
+public:
+    DECLARE_EXCEPTION_TYPE(SecurityServer::Exception, Base)
+    DECLARE_EXCEPTION_TYPE(Base, InvalidAction)
+};
+
+class InstallerService :
+    public SecurityServer::GenericSocketService,
+    public SecurityServer::ServiceThread<InstallerService>
+{
+public:
+    InstallerService();
+    ServiceDescriptionVector GetServiceDescription();
+
+    DECLARE_THREAD_EVENT(AcceptEvent, accept)
+    DECLARE_THREAD_EVENT(WriteEvent, write)
+    DECLARE_THREAD_EVENT(ReadEvent, process)
+    DECLARE_THREAD_EVENT(CloseEvent, close)
+
+    void accept(const AcceptEvent &event);
+    void write(const WriteEvent &event);
+    void process(const ReadEvent &event);
+    void close(const CloseEvent &event);
+
+private:
+    ConnectionInfoMap m_connectionInfoMap;
+
+    /**
+     * 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);
+
+    /**
+     * Process application installation
+     *
+     * @param  buffer Raw received data buffer
+     * @param  send   Raw data buffer to be sent
+     * @return        true on success
+     */
+    bool processAppInstall(MessageBuffer &buffer, MessageBuffer &send);
+
+    /**
+     * Process libprivilege-control action and store result in a bufer
+     *
+     * @param  buffer Raw received data buffer
+     * @param  send   Raw data buffer to be sent
+     * @return        true on success
+     */
+    bool processAppUninstall(MessageBuffer &buffer, MessageBuffer &send);
+};
+
+} // namespace SecurityServer
+
+#endif // _SECURITY_SERVER_INSTALLER_
index 52d95a5..e2ebc7a 100644 (file)
@@ -10,6 +10,7 @@ INSTALL(FILES
     ${CMAKE_SOURCE_DIR}/systemd/security-server-password-reset.socket
     ${CMAKE_SOURCE_DIR}/systemd/security-server-password-check.socket
     ${CMAKE_SOURCE_DIR}/systemd/security-server-password-set.socket
+    ${CMAKE_SOURCE_DIR}/systemd/security-manager-installer.socket
     DESTINATION
     /usr/lib/systemd/system
 )
diff --git a/systemd/security-manager-installer.socket b/systemd/security-manager-installer.socket
new file mode 100644 (file)
index 0000000..5f75233
--- /dev/null
@@ -0,0 +1,15 @@
+[Socket]
+ListenStream=/tmp/.security-manager-api-installer.sock
+SocketMode=0777
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+
+# TODO: move to separate systemd service
+Service=security-server.service
+
+[Unit]
+Wants=security-server.target
+Before=security-server.target
+
+[Install]
+WantedBy=sockets.target
index 676942a..6c74174 100644 (file)
@@ -13,6 +13,7 @@ Sockets=security-server-cookie-check.socket
 Sockets=security-server-password-check.socket
 Sockets=security-server-password-set.socket
 Sockets=security-server-password-reset.socket
+Sockets=security-manager-installer.socket # TODO: move to separate systemd service
 
 [Install]
 WantedBy=multi-user.target