Add ipc library for ask-user 14/120914/11
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 24 Mar 2017 16:30:07 +0000 (17:30 +0100)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 31 Mar 2017 16:43:40 +0000 (18:43 +0200)
This library is used in communication between privacy denied
plugin/security manager and ask user service.

Change-Id: If9e71a3a716095eba8b909cc28d08a1853ba2951

13 files changed:
src/common/protocol/CMakeLists.txt [new file with mode: 0644]
src/common/protocol/ask-user-client.cpp [new file with mode: 0644]
src/common/protocol/ask-user-config.cpp [new file with mode: 0644]
src/common/protocol/ask-user-config.h [new file with mode: 0644]
src/common/protocol/ask-user/ask-user-client.h [new file with mode: 0644]
src/common/protocol/ask-user/ask-user-service.h [new file with mode: 0644]
src/common/protocol/ask-user/ask-user-types.h [new file with mode: 0644]
src/common/protocol/channel.cpp [new file with mode: 0644]
src/common/protocol/channel.h [new file with mode: 0644]
src/common/protocol/main.cpp [new file with mode: 0644]
src/common/protocol/raw-buffer.h [new file with mode: 0644]
src/common/protocol/sock.cpp [new file with mode: 0644]
src/common/protocol/sock.h [new file with mode: 0644]

diff --git a/src/common/protocol/CMakeLists.txt b/src/common/protocol/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eef74f9
--- /dev/null
@@ -0,0 +1,33 @@
+SET(TARGET_PROTOCOL "protocol")
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -ggdb -O0")
+
+INCLUDE_DIRECTORIES(
+    ${PROJECT_SOURCE_DIR}
+  )
+
+SET(PROTOCOL_SOURCES
+    ${PROJECT_SOURCE_DIR}/channel.cpp
+    ${PROJECT_SOURCE_DIR}/ask-user-client.cpp
+    ${PROJECT_SOURCE_DIR}/sock.cpp
+    ${PROJECT_SOURCE_DIR}/ask-user-config.cpp
+  )
+
+ADD_LIBRARY(${TARGET_PROTOCOL} SHARED ${PROTOCOL_SOURCES})
+
+TARGET_LINK_LIBRARIES(${TARGET_PROTOCOL})
+
+
+SET(TARGET_PTEST "test")
+
+SET(TARGET_PTEST_SOURCES
+    ${PROJECT_SOURCE_DIR}/main.cpp
+  )
+
+ADD_EXECUTABLE(${TARGET_PTEST} ${TARGET_PTEST_SOURCES})
+
+TARGET_LINK_LIBRARIES(${TARGET_PTEST} ${TARGET_PROTOCOL})
+
+
+
+
diff --git a/src/common/protocol/ask-user-client.cpp b/src/common/protocol/ask-user-client.cpp
new file mode 100644 (file)
index 0000000..4c77db9
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ipc-client.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#include <sstream>
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <ask-user/ask-user-client.h>
+#include <ask-user/ask-user-service.h>
+
+#include <ask-user-config.h>
+#include <sock.h>
+
+namespace AskUser {
+namespace Protocol {
+
+int popup_launch(const std::string &pkgName,
+                 const std::string &appName,
+                 uid_t uid,
+                 const PrivilegeVector &privileges,
+                 int &result)
+{
+    try {
+        std::string path = SOCKET_STREAM_PATH + "." + std::to_string(uid);
+        Sock s(Sock::CLI_STREAM);
+        if (0 > s.connect(path))
+            return -1;
+
+        std::stringstream ss;
+        ss << MSGID_POPUP << " " << pkgName << " " << appName << " " << uid;
+        for (auto &e : privileges) {
+            ss << " " << e;
+        }
+
+        std::string str = ss.str();
+
+        if (0 > s.send(RawBuffer(str.begin(), str.end())))
+            return -1;
+
+        RawBuffer resp;
+        if (0 > s.wait(FdMask::READ))
+            return -1;
+        if (0 > s.recv(resp))
+            return -1;
+
+        std::string input(resp.begin(), resp.end());
+        std::stringstream sss(input);
+        sss >> result;
+
+        return 0;
+    } catch (const std::exception &) {
+        return -1;
+    }
+}
+
+int popup_runtime(const std::string &pkgName,
+                  const std::string &appName,
+                  uid_t uid,
+                  std::string &privilege,
+                  int &result)
+{
+    return -1;
+}
+
+
+int toast_deny(const std::string &pkgName,
+               const std::string &appName,
+               uid_t uid,
+               const std::string &privilege)
+{
+    try {
+        std::string path = SOCKET_DGRAM_PATH + "." + std::to_string(uid);
+        Sock s(Sock::CLI_DGRAM);
+        if (0 > s.connect(path))
+            return -1;
+
+        std::string str = std::to_string(MSGID_TOAST1) + " " + pkgName + " " + appName + " " + std::to_string(uid) + " " + privilege;
+
+        return s.send(RawBuffer(str.begin(), str.end()));
+    } catch (const std::exception &) {
+        return -1;
+    }
+}
+
+int toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid) {
+    try {
+        std::string path = SOCKET_DGRAM_PATH + "." + std::to_string(uid);
+        Sock s(Sock::CLI_DGRAM);
+        if (0 > s.connect(path))
+            return -1;
+
+        std::string str = std::to_string(MSGID_TOAST2) + " " + pkgName + " " + appName + " " + std::to_string(uid);
+
+        return s.send(RawBuffer(str.begin(), str.end()));
+    } catch (const std::exception &) {
+        return -1;
+    }
+}
+
+} // namespace Protocol
+} // namespace AskUser
+
+
diff --git a/src/common/protocol/ask-user-config.cpp b/src/common/protocol/ask-user-config.cpp
new file mode 100644 (file)
index 0000000..415f1a5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ask-user-config.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#include <ask-user-config.h>
+
+const std::string SOCKET_STREAM_PATH("/tmp/ask-user-stream");
+const std::string SOCKET_DGRAM_PATH("/tmp/ask-user-dgram");
+
+//const int MSGID_POPUP = 1;
+//const int MSGID_TOUST1 = 2;
+//const int MSGID_TOUST2 = 3;
+//
diff --git a/src/common/protocol/ask-user-config.h b/src/common/protocol/ask-user-config.h
new file mode 100644 (file)
index 0000000..0205bb3
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ask-user-config.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#include <string>
+
+extern const std::string SOCKET_STREAM_PATH;
+extern const std::string SOCKET_DGRAM_PATH;
+
+// We want to use it constat expressions (this is the reason why it's not in cpp file
+const int MSGID_POPUP = 1;
+const int MSGID_TOAST1 = 2;
+const int MSGID_TOAST2 = 3;
+
diff --git a/src/common/protocol/ask-user/ask-user-client.h b/src/common/protocol/ask-user/ask-user-client.h
new file mode 100644 (file)
index 0000000..15b9e44
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ask-user-client.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <ask-user/ask-user-types.h>
+
+namespace AskUser {
+namespace Protocol {
+/**
+ * Synchronous request for showing popup.
+ *
+ * \param[in] pkgName    Application package name.
+ * \param[in] appName    Application name.
+ * \param[in] uid        Information about user that should see popup.
+ * \param[in] privileges List of privileges that should be shown to user.
+ * \param[out] result    Result returned by ask-user application.
+ *
+ * \return Value less that 0 means ipc error.
+ */
+ int popup_launch(const std::string &pkgName, const std::string &appName, uid_t uid, const PrivilegeVector &privileges, int &result);
+
+ /**
+  * Synchronous request for showing popup.
+  *
+  * \param[in] pkgName    Application package name.
+  * \param[in] appName    Application name.
+  * \param[in] uid        Information about user that should see popup.
+  * \param[in] privilege  Privilege that should be shown to user.
+  * \param[out] result    Result returned by ask-user application.
+  *
+  * \return Value less that 0 means ipc error.
+  */
+ int popup_runtime(const std::string &pkgName, const std::string &appName, uid_t uid, std::string &privilege, int &result);
+
+/**
+ * Nonblocking request for showing toast.
+ *
+ * \param[in] pkgName    Application package name.
+ * \param[in] appName    Application name.
+ * \param[in] uid        Information about user that should see popup.
+ * \param[in] privilege  Name of privilege that was denied.
+ *
+ * \return Value less that 0 means ipc error.
+ */
+int toast_deny(const std::string &pkgName, const std::string &appName, uid_t uid, const std::string &privilege);
+
+/**
+ * Nonblocking request for showing toast.
+ *
+ * \param[in] pkgName    Application package name.
+ * \param[in] appName    Application name.
+ * \param[in] uid        Information about user that should see popup.
+ *
+ * \return Value less that 0 means ipc error.
+ */
+int toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid);
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/ask-user/ask-user-service.h b/src/common/protocol/ask-user/ask-user-service.h
new file mode 100644 (file)
index 0000000..ca9b704
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ask-user-service.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <ask-user/ask-user-types.h>
+
+namespace AskUser {
+namespace Protocol {
+
+enum FdMask {
+    READ = 1,
+    WRITE = 2,
+};
+
+/**
+ * IServiceCallbacks defines set of callbacks that must be implemented in service.
+ */
+
+struct IServerCallbacks {
+
+    virtual ~IServerCallbacks(){}
+    /**
+     * This function gives you number of descriptor that should be watched by poll/select.
+     *
+     * \param[in] fd   Number of opened descriptor.
+     * \param[in] mask Type of acction that is required on this descriptor.
+     *           mask == 0 remove descriptor fd from watched pool
+     *           mask == 1 watch descriptor for READ
+     *           mask == 2 watch descriptor for WRITE
+     *           maks == 3 watch descriptor for READ and WRITE
+     */
+    virtual void updateFd(int fd, int mask) = 0;
+    /**
+     * some client called popup function with parameters.
+     */
+    virtual void popup_launch(int requestId, const std::string &pkgName, const std::string &appName, uid_t uid, const PrivilegeVector &privileges) = 0;
+    /**
+     * some client called test_deny function with parameters.
+     */
+     virtual void toast_deny(const std::string &pkgName, const std::string &appName, uid_t uid, const Privilege &privilege) = 0;
+    /**
+     * some client called toast_fail_launch function with parameters.
+     */
+     virtual void toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid) = 0;
+};
+
+struct IChannel {
+    virtual ~IChannel(){}
+
+    /**
+     * Process function should be called each time some event is reported by poll/select on
+     * descriptor.
+     *
+     * \param[in] fd    Number of descriptor.
+     * \param[in] mask  Information about event that is waiting on descriptor
+     *                 (FdMask::READ or FdMask::WRITE). If you pass 0 for some reason
+     *                 the descriptor will be closed and callback updateFd will be called
+     *                 with mask = 0
+     */
+    virtual void process(int fd, int mask) = 0;
+
+    /**
+     * Information about action that was choosed by user.
+     *
+     * \param[in] requestId  Request number.
+     * \param[in] response   Information about action choosed by user.
+     */
+    virtual void popupResponse(int requestId, int response) = 0;
+};
+
+typedef std::unique_ptr<IChannel> ChannelPtr;
+typedef std::unique_ptr<IServerCallbacks> ServerCallbacksPtr;
+
+ChannelPtr createChannel(ServerCallbacksPtr ptr);
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/ask-user/ask-user-types.h b/src/common/protocol/ask-user/ask-user-types.h
new file mode 100644 (file)
index 0000000..642667c
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        ask-user-types.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#define ASKUSER_DENY_ONCE 0
+#define ASKUSER_DENY_FOREVER 1
+#define ASKUSER_ALLOW_ONCE 2
+#define ASKUSER_ALLOW_FOREVER 3
+#define ASKUSER_UNKNOWN_ERROR -255
+
+namespace AskUser {
+namespace Protocol {
+
+typedef std::string Privilege;
+typedef std::vector<Privilege> PrivilegeVector;
+
+} // namespace Protocol
+} // AskUser
+
diff --git a/src/common/protocol/channel.cpp b/src/common/protocol/channel.cpp
new file mode 100644 (file)
index 0000000..7b7e726
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        channel.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#include <sstream>
+#include <string>
+
+#include <ask-user/ask-user-service.h>
+
+#include <ask-user-config.h>
+#include <channel.h>
+#include <sock.h>
+
+namespace AskUser {
+namespace Protocol {
+
+void Channel::init() {
+    Sock stream(Sock::SRV_STREAM);
+    Sock datagram(Sock::SRV_DGRAM);
+
+    uid_t uid = getuid();
+    std::string path = SOCKET_STREAM_PATH + "." + std::to_string(uid);
+    stream.connect(path);
+    path = SOCKET_DGRAM_PATH + "." + std::to_string(uid);
+    datagram.connect(path);
+
+    int fd1 = stream.getFd();
+    int fd2 = datagram.getFd();
+
+    m_socket[fd1] = SockDesc(std::move(stream));
+    m_socket[fd2] = SockDesc(std::move(datagram));
+
+    m_callbacks->updateFd(fd1, FdMask::READ);
+    m_callbacks->updateFd(fd2, FdMask::READ);
+}
+
+void Channel::process(int fd, int mask) {
+    try {
+        auto it = m_socket.find(fd);
+        if (it == m_socket.end())
+            return;
+
+        if (0 == mask) {
+            m_socket.erase(it);
+            m_callbacks->updateFd(fd, 0);
+            return;
+        }
+
+        auto &desc = it->second;
+
+        if (desc.sock.getType() == Sock::SRV_STREAM) {
+            Sock client = desc.sock.accept();
+            int fd = client.getFd();
+            if (fd < 0)
+                return;
+            m_socket[fd] = SockDesc(std::move(client));
+            m_callbacks->updateFd(fd, FdMask::READ);
+            return;
+        }
+
+        if (mask & FdMask::READ) {
+            int ret = desc.sock.recv(desc.input);
+
+            if (ret <= 0) {
+                m_socket.erase(fd);
+                m_callbacks->updateFd(fd, 0);
+                return;
+            }
+
+            std::string data(desc.input.begin(), desc.input.end());
+            desc.input.clear();
+            std::stringstream ss(data);
+
+            int command;
+            std::string appId, pkgName;
+            uid_t uid;
+
+            ss >> command >> pkgName >> appId >> uid;
+
+            switch(command) {
+            case MSGID_POPUP:
+                {
+                    PrivilegeVector vect;
+                    std::string privilege;
+                    while(ss) {
+                        ss >> privilege;
+                        vect.push_back(privilege);
+                    }
+                    m_callbacks->popup_launch(fd, pkgName, appId, uid, vect);
+                    break;
+                }
+            case MSGID_TOAST1:
+                {
+                    std::string privilege;
+                    ss >> privilege;
+                    m_callbacks->toast_deny(pkgName, appId, uid, privilege);
+                    break;
+                }
+            case MSGID_TOAST2:
+                {
+                    m_callbacks->toast_fail_launch(pkgName, appId, uid);
+                    break;
+                }
+            }
+        }
+
+        if (mask & FdMask::WRITE) {
+            int size = static_cast<int>(desc.output.size());
+            int result = desc.sock.send(desc.output);
+            if (result < 0) {
+                m_socket.erase(fd);
+                m_callbacks->updateFd(fd, 0);
+                return;
+            }
+
+            if (result == size) {
+                desc.output.clear();
+                m_callbacks->updateFd(fd, FdMask::READ);
+            }
+
+            if (result < size) {
+                desc.output.erase(desc.output.begin(), desc.output.begin()+result);
+            }
+        }
+    } catch (const std::exception &){}
+}
+
+void Channel::popupResponse(int requestId, int response) {
+    try {
+        auto it = m_socket.find(requestId);
+        if (it == m_socket.end())
+            return;
+
+        auto &desc = it->second;
+
+        std::stringstream ss;
+        ss << response;
+        std::string o = ss.str();
+
+        std::copy(o.begin(), o.end(), std::back_inserter(desc.output));
+        m_callbacks->updateFd(requestId, FdMask::READ | FdMask::WRITE);
+    } catch (const std::exception &){}
+}
+
+Channel::~Channel() {
+    for (auto &e : m_socket)
+        m_callbacks->updateFd(e.first, 0);
+}
+
+ChannelPtr createChannel(ServerCallbacksPtr ptr) {
+    try {
+        Channel *c = new Channel(std::move(ptr));
+        c->init();
+        return ChannelPtr(c);
+    } catch (const std::exception &) {
+        return ChannelPtr(nullptr);
+    }
+}
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/channel.h b/src/common/protocol/channel.h
new file mode 100644 (file)
index 0000000..8898155
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        channel.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <ask-user/ask-user-service.h>
+#include <raw-buffer.h>
+#include <sock.h>
+
+
+namespace AskUser {
+namespace Protocol {
+
+struct SockDesc {
+    SockDesc(Sock psock)
+      : sock(std::move(psock))
+    {}
+    SockDesc(){}
+    Sock sock;
+    RawBuffer input;
+    RawBuffer output;
+};
+
+typedef std::map<int, SockDesc> SocketMap;
+
+class Channel : public IChannel {
+public:
+    Channel(ServerCallbacksPtr ptr)
+      : m_callbacks(std::move(ptr))
+    {}
+
+    void init();
+    virtual void process(int fd, int mask);
+    virtual void popupResponse(int requestId, int response);
+    virtual ~Channel();
+
+private:
+    ServerCallbacksPtr m_callbacks;
+    SocketMap m_socket;
+};
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/main.cpp b/src/common/protocol/main.cpp
new file mode 100644 (file)
index 0000000..d733494
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        main.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#include <map>
+
+#include <poll.h>
+#include <unistd.h>
+
+#include <ask-user/ask-user-client.h>
+#include <ask-user/ask-user-service.h>
+
+std::map<int, int> m_sockets;
+
+using namespace AskUser::Protocol;
+
+struct Callbacks : public IServerCallbacks {
+    Callbacks() : m_channel(nullptr) {}
+
+    virtual void updateFd(int fd, int mask) {
+        printf("call updateFd %d %d\n", fd, mask);
+        if (mask == 0) {
+            m_sockets.erase(fd);
+            return;
+        }
+        m_sockets[fd] = mask;
+    }
+
+    virtual void popup_launch(int requestId, const std::string &pkgName, const std::string &appName, uid_t uid, const PrivilegeVector &priv) {
+        printf("call popup %s %s %d\n", pkgName.c_str(), appName.c_str(), uid);
+        if (m_channel)
+            m_channel->popupResponse(requestId, 0xdeadbeef);
+    }
+
+    virtual void toast_deny(const std::string &pkgName, const std::string &appName, uid_t uid, const Privilege &privilege) {
+        printf("call toast_deny %s %s %d\n", pkgName.c_str(), appName.c_str(), uid);
+    }
+
+    virtual void toast_fail_launch(const std::string &pkgName, const std::string &appName, uid_t uid) {
+        printf("call toast_fail_launch %s %s %d\n", pkgName.c_str(), appName.c_str(), uid);
+    }
+
+    void setChannel(IChannel *ptr) {
+        m_channel = ptr;
+    }
+
+private:
+    IChannel *m_channel;
+};
+
+void server(void) {
+    Callbacks *c = new Callbacks;
+    ChannelPtr ptr = createChannel(ServerCallbacksPtr(c));
+    c->setChannel(ptr.get());
+
+    pollfd fd[100];
+
+    while(1) {
+        int last = 0;
+        for (auto &e : m_sockets) {
+            fd[last].fd = e.first;
+            fd[last].revents = 0;
+            fd[last].events = ((e.second & FdMask::READ) ? POLLIN : 0) | ((e.second & FdMask::WRITE) ? POLLOUT : 0);
+            last++;
+        }
+        if (-1 == poll(fd, last, -1)) {
+            printf("Error in poll. Quit\n");
+            return;
+        }
+        for (int i=0; i<last; ++i) {
+            if (fd[i].revents & POLLIN)
+                ptr->process(fd[i].fd, FdMask::READ);
+            if (fd[i].revents & POLLOUT)
+                ptr->process(fd[i].fd, FdMask::WRITE);
+        }
+    }
+}
+
+void stream() {
+    PrivilegeVector vect = {"one", "two"};
+    int result;
+    int ret = popup_launch("spkg", "sapp", getuid(), vect, result);
+    printf("Sended stream. Result: %x\n", result);
+}
+
+void toust1() {
+    toast_deny("tpkg1", "sapp1", getuid(), "some_priv");
+    printf("sended\n");
+}
+
+void toust2() {
+    toast_fail_launch("tpkg2", "sapp2", getuid());
+    printf("sended\n");
+}
+
+int main(){
+    int com;
+    printf("0 - server, 1 - send stream, 2 - send toust1, 3 - send toust2\n>");
+    scanf("%d", &com);
+
+    switch(com) {
+    case 0:
+        server();
+        break;
+    case 1:
+        stream();
+        break;
+    case 2:
+        toust1();
+        break;
+    case 3:
+        toust2();
+        break;
+    }
+
+    return 0;
+}
diff --git a/src/common/protocol/raw-buffer.h b/src/common/protocol/raw-buffer.h
new file mode 100644 (file)
index 0000000..8c2c779
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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        raw-buffer.h
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief
+ */
+#pragma once
+
+#include <vector>
+
+namespace AskUser {
+namespace Protocol {
+
+typedef std::vector<unsigned char> RawBuffer;
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/sock.cpp b/src/common/protocol/sock.cpp
new file mode 100644 (file)
index 0000000..cde563a
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief       Implementation of Sock methods
+ */
+#include <poll.h>
+#include <stdexcept>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#ifdef WITH_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif // WITH_SYSTEMD
+
+#include <string>
+#include <vector>
+
+#include <ask-user/ask-user-service.h>
+
+#include <sock.h>
+
+namespace {
+
+int getSocketFromSystemD() {
+#ifdef WITH_SYSTEMD
+    int n = sd_listen_fds(0);
+
+    if (n < 0)
+        return -1;
+
+    for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+n; ++fd)
+        if (0 < sd_is_socket_unix(fd, getUnixSockType, 1, m_path.c_str(), 0))
+            return fd;
+#endif // WITH_SYSTEMD
+    return -1;
+}
+
+} // namespace Anonymous
+
+namespace AskUser {
+namespace Protocol {
+
+Sock::Sock(Sock &&second)
+  : m_type(second.m_type)
+  , m_fd(second.m_fd)
+{
+    second.m_fd = -1;
+}
+
+Sock::Sock(Sock::Type type, int fd)
+  : m_type(type)
+  , m_fd(fd)
+{}
+
+Sock& Sock::operator=(Sock &&second) {
+    if (this == &second)
+        return *this;
+
+    close();
+
+    m_fd = second.m_fd;
+    m_type = second.m_type;
+
+    second.m_fd = -1;
+
+    return *this;
+}
+
+
+int Sock::getUnixSockType() const {
+    switch(m_type) {
+    case SRV_DGRAM:
+    case CLI_DGRAM:
+        return SOCK_DGRAM;
+    case SRV_STREAM:
+    case CLI_STREAM:
+        return SOCK_STREAM;
+    }
+    return 0;
+}
+
+int Sock::connect(const std::string &path) {
+    if (m_fd != -1)
+        return -1;
+
+    m_path = path;
+
+    bool policySystemD = true;
+    bool policyUnlink  = true;
+    bool policySocket  = true;
+    bool policyBind    = true;
+    bool policyListen  = true;
+    bool policyConnect = true;
+
+    switch(m_type) {
+    case SRV_STREAM:
+        policyConnect = false;
+        break;
+    case CLI_STREAM:
+        policySystemD = false;
+        policyUnlink  = false;
+        policyBind    = false;
+        policyListen  = false;
+        break;
+    case SRV_DGRAM:
+        policyListen  = false;
+        policyConnect = false;
+        break;
+    case CLI_DGRAM:
+        policySystemD = false;
+        policyUnlink  = false;
+        policyBind    = false;
+        policyListen  = false;
+        policyConnect = false;
+        break;
+    }
+
+    if (m_fd != -1) {
+        return -1;
+    }
+
+    if (policySystemD) {
+        m_fd = getSocketFromSystemD();
+        if (m_fd >= 0) {
+            policyUnlink = false;
+            policySocket = false;
+            policyBind = false;
+        }
+    }
+
+    if (policyUnlink)
+        ::unlink(m_path.c_str());  // we ignore return value by design
+
+    if (policySocket)
+        m_fd = ::socket(AF_UNIX, getUnixSockType(), 0);
+
+    if (m_fd < 0)
+        return -1;
+
+    // remote is used in bind and in connect
+    sockaddr_un remote;
+    auto length = sizeof(sockaddr_un);
+    if (policyBind || policyConnect) {
+        remote.sun_family = AF_UNIX;
+        if (path.size() >= sizeof(remote.sun_path)) {
+            close();
+            return -1;
+        }
+        memcpy(remote.sun_path, path.c_str(), path.size()+1);
+    }
+
+    if (policyBind && (-1 == ::bind(m_fd, reinterpret_cast<sockaddr *>(&remote), sizeof(remote)))) {
+        close();
+        return -1;
+    }
+
+    if (policyListen && (-1 == ::listen(m_fd, 5))) {
+        close();
+        return -1;
+    }
+
+    if (policyConnect && (-1 == TEMP_FAILURE_RETRY(::connect(m_fd, reinterpret_cast<sockaddr *>(&remote), static_cast<socklen_t>(length)))))
+    {
+        close();
+        return -1;
+    }
+    return 0;
+}
+
+Sock Sock::accept() {
+    int retFd = TEMP_FAILURE_RETRY(::accept(m_fd, nullptr, nullptr));
+    if (retFd < 0) {
+        return Sock(CLI_STREAM, -1);
+    }
+    return Sock(CLI_STREAM, retFd);
+}
+
+int Sock::send(const RawBuffer &buffer) {
+    static const int flags = MSG_NOSIGNAL | MSG_DONTWAIT;
+    if (m_fd < 0)
+        return -1;
+
+    switch(m_type) {
+    default:
+        return -1;
+    case CLI_STREAM:
+        {
+            return static_cast<int>(
+                TEMP_FAILURE_RETRY(::send(m_fd, buffer.data(), buffer.size(), flags)));
+        }
+    case CLI_DGRAM:
+        {
+            struct sockaddr_un addr;
+            memset(&addr, 0, sizeof(addr));
+            addr.sun_family = AF_UNIX;
+            memcpy(addr.sun_path, m_path.data(), m_path.size());
+            return static_cast<int>(
+                TEMP_FAILURE_RETRY(::sendto(m_fd, buffer.data(), buffer.size(), flags,
+                            reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr))));
+        }
+    }
+}
+
+int Sock::wait(int mask) {
+    pollfd fd = {};
+
+    fd.fd = m_fd;
+    fd.events = (mask & FdMask::READ ? POLLIN : 0) | (mask & FdMask::WRITE ? POLLOUT : 0);
+
+    if (fd.events == 0)
+        return -1;
+
+    if (0 > ::poll(&fd, 1, -1))
+        return -1;
+    return 0;
+}
+
+int Sock::recv(RawBuffer &output) {
+    if (m_fd < 0)
+        return -1;
+
+    switch(m_type) {
+    default:
+        return -1;
+    case CLI_STREAM:
+    case SRV_DGRAM:
+        {
+            RawBuffer buffer(4096);
+            int result = TEMP_FAILURE_RETRY(::recv(m_fd, buffer.data(), buffer.size(), MSG_DONTWAIT));
+            if (result > 0)
+                std::copy(buffer.begin(), buffer.begin()+result, std::back_inserter(output));
+            return static_cast<int>(result);
+        }
+    }
+}
+
+void Sock::close() {
+    if (m_fd >= 0)
+        ::close(m_fd);
+    m_fd = -1;
+}
+
+} // namespace Protocol
+} // namespace AskUser
+
diff --git a/src/common/protocol/sock.h b/src/common/protocol/sock.h
new file mode 100644 (file)
index 0000000..499bf1c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2017 Samsung Electronics Co.
+ *
+ *  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.cpp
+ * @author      Bartlomiej Grzelewski <b.grzelewski@samsung.com>
+ * @brief       Declaration of client/server Sock wrapper
+ */
+
+#pragma once
+
+#include <string>
+#include <unistd.h>
+
+#include <raw-buffer.h>
+
+namespace AskUser {
+namespace Protocol {
+
+class Sock {
+public:
+    enum Type {
+        SRV_STREAM,      // server side STREAM socket (you may call accept on it)
+                         // accept will always return CLI_STREAM
+        CLI_STREAM,      // client side STREAM socket
+        SRV_DGRAM,       // server side DATAGRAM socket
+        CLI_DGRAM,       // client side DATAGRAM socket
+    };
+
+    Sock(Type type = SRV_STREAM, int fd = -1);
+
+    Sock(const Sock &other) = delete;
+    Sock &operator=(const Sock &other) = delete;
+
+    Sock(Sock &&other);
+    Sock &operator=(Sock &&other);
+
+    virtual ~Sock() { close(); }
+
+    int getFd() const { return m_fd; }
+    int getType() const { return m_type; }
+    int getUnixSockType() const;
+
+
+    int connect(const std::string &path);
+    Sock accept();
+    void close();
+
+    int wait(int mask);
+    int recv(RawBuffer &buffer);
+    int send(const RawBuffer &buffer);
+
+private:
+    Type m_type;
+    int m_fd;
+    std::string m_path;
+};
+
+} // namespace Protocol
+} // namespace AskUser
+