Add AccessController Class 56/166256/5
authorInkyun Kil <inkyun.kil@samsung.com>
Tue, 9 Jan 2018 04:21:39 +0000 (13:21 +0900)
committerInkyun Kil <inkyun.kil@samsung.com>
Fri, 12 Jan 2018 02:09:19 +0000 (11:09 +0900)
Change-Id: I787024d9195cf59ec4bd613f4815d004d3045e59
Signed-off-by: Inkyun Kil <inkyun.kil@samsung.com>
CMakeLists.txt
include/rpc-port.h
packaging/rpc-port.spec
src/ac-internal.cc [new file with mode: 0644]
src/ac-internal.h [new file with mode: 0644]
src/fdbroker-internal.cc
src/fdbroker-internal.h
src/rpc-port.cc
src/stub-internal.cc
src/stub-internal.h
unit_tests/src/rpc_port_test.cc

index a9527d3..d787267 100644 (file)
@@ -6,7 +6,7 @@ INCLUDE_DIRECTORIES (
        ${CMAKE_SOURCE_DIR}/src
        )
 
-SET(${this_target}_requires "dlog bundle glib-2.0 gio-2.0 aul capi-base-common pkgmgr-info gio-unix-2.0")
+SET(${this_target}_requires "dlog bundle glib-2.0 gio-2.0 aul capi-base-common pkgmgr-info gio-unix-2.0 cynara-client cynara-creds-gdbus")
 
 INCLUDE(FindPkgConfig)
 pkg_check_modules(${this_target} REQUIRED ${${this_target}_requires})
index c20f07d..70ee743 100755 (executable)
@@ -57,6 +57,7 @@ typedef int (*rpc_port_stub_received_event_cb)(const char *sender,
 int rpc_port_stub_create(rpc_port_stub_h *h, const char *port_name);
 int rpc_port_stub_destroy(rpc_port_stub_h h);
 int rpc_port_stub_listen(rpc_port_stub_h h);
+int rpc_port_stub_add_privilege(rpc_port_stub_h h, const char *privilege);
 int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h,
                rpc_port_stub_connected_event_cb cb, void *data);
 int rpc_port_stub_add_disconnected_event_cb(rpc_port_stub_h h,
index 282fc9d..e449e27 100755 (executable)
@@ -14,6 +14,8 @@ BuildRequires:  pkgconfig(aul)
 BuildRequires:  pkgconfig(pkgmgr)
 BuildRequires:  pkgconfig(pkgmgr-info)
 BuildRequires:  pkgconfig(gmock)
+BuildRequires:  pkgconfig(cynara-client)
+BuildRequires:  pkgconfig(cynara-creds-gdbus)
 
 Requires(post): /sbin/ldconfig
 Requires(post): coreutils
diff --git a/src/ac-internal.cc b/src/ac-internal.cc
new file mode 100644 (file)
index 0000000..7ce273c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <dlog.h>
+#include <cynara-error.h>
+#include <cynara-creds-gdbus.h>
+
+#include "ac-internal.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RPC_PORT"
+
+namespace rpc_port {
+namespace internal {
+
+AccessController::~AccessController() {}
+
+void AccessController::AddPrivilege(const std::string& privilege) {
+  privileges_.push_back(privilege);
+}
+
+int AccessController::CheckPrivilege(GDBusConnection *connection, const char* sender_appid) {
+  Cynara c;
+
+  if (c.FetchCredsFromDBus(connection, sender_appid) != 0 )
+    return -1;
+
+  for (auto& privilege : privileges_) {
+    if (c.Check(privilege) != 0) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+int AccessController::SetCache(const std::string& sender) {
+  return -1;
+}
+
+AccessController::Cynara::Cynara() {
+  cynara_ = nullptr;
+  client_ = nullptr;
+  user_ = nullptr;
+
+  if (cynara_initialize(&cynara_, NULL) != CYNARA_API_SUCCESS) {
+    LOGE("cynara_initialize() is failed");
+  }
+}
+
+AccessController::Cynara::~Cynara() {
+  if (client_)
+    free(client_);
+  if (user_)
+    free(user_);
+  if (cynara_)
+    cynara_finish(cynara_);
+}
+
+int AccessController::Cynara::FetchCredsFromDBus(GDBusConnection *connection, const char *sender_appid) {
+  int ret;
+
+  if (client_) {
+    free(client_);
+     client_ = nullptr;
+  }
+
+  if (user_) {
+    free(user_);
+    user_ = nullptr;
+  }
+
+  ret = cynara_creds_gdbus_get_user(connection, sender_appid, USER_METHOD_DEFAULT, &user_);
+  if (ret != CYNARA_API_SUCCESS) {
+    LOGE("cynara_creds_gdbus_get_user() is failed : %d", ret);
+    return -1;
+  }
+
+  ret = cynara_creds_gdbus_get_client(connection, sender_appid, CLIENT_METHOD_DEFAULT, &client_);
+  if (ret != CYNARA_API_SUCCESS) {
+    LOGE("cynara_creds_gdbus_get_client() is failed : %d", ret);
+    return -1;
+  }
+
+  LOGD("cred client : %s, cred user : %s", client_, user_);
+  return 0;
+}
+
+int AccessController::Cynara::Check(const std::string& privilege) {
+  LOGD("check %s", privilege.c_str());
+  if (cynara_check(cynara_, client_, "", user_, privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) {
+    LOGE("cynara_check() is failed : %s", privilege.c_str());
+    return -1;
+  }
+
+  return 0;
+}
+
+}  // namespace internal
+}  // namespace rpc_port
diff --git a/src/ac-internal.h b/src/ac-internal.h
new file mode 100644 (file)
index 0000000..1948ff0
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef AC_INTERNAL_H_
+#define AC_INTERNAL_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-unix.h>
+#include <cynara-client.h>
+
+#include <string>
+#include <vector>
+#include <map>
+
+namespace rpc_port {
+namespace internal {
+
+class AccessController {
+ public:
+  virtual ~AccessController();
+
+  void AddPrivilege(const std::string& privilege);
+  int CheckPrivilege(GDBusConnection *connection, const char* sender_appid);
+
+ private:
+  int SetCache(const std::string& sender);
+
+  class Cynara {
+   public:
+     Cynara();
+     ~Cynara();
+
+     int FetchCredsFromDBus(GDBusConnection *connection, const char *sender_appid);
+     int Check(const std::string& privilege);
+
+   private:
+     cynara *cynara_;
+     char *client_;
+     char *user_;
+  };
+
+ private:
+  std::vector<std::string> privileges_;
+  std::map<std::string, bool> cache_;
+};
+
+}  // namespace internal
+}  // namespace rpc_port
+
+#endif  // AC_INTERNAL_H_
index 77ecf6f..26c08f3 100644 (file)
@@ -200,7 +200,7 @@ std::string FdBroker::GetInterfaceName(const std::string& target_appid,
   char c_buf[interface_name.length() * 2 + 1] = {0};
   char* temp = &c_buf[0];
 
-  for (int index = 0; index < interface_name.length(); index++) {
+  for (unsigned int index = 0; index < interface_name.length(); index++) {
     snprintf(temp, 3, "%02x", interface_name[index]);
     temp += 2;
   }
@@ -212,11 +212,14 @@ int FdBroker::Send(const std::string& target_appid,
                    const std::string& port_name) {
   std::string interface_name = GetInterfaceName(target_appid, port_name);
   GDBusMessage *msg;
+  GDBusMessage *reply;
   GError *err = nullptr;
   GVariant *body;
+  GVariant *reply_body;
   SocketPair sock_pair(mock_);
   FdList fd_list;
   char sender_appid[255];
+  int ret;
 
   if (!mock_ && aul_app_get_appid_bypid(getpid(),
        sender_appid, sizeof(sender_appid)) < 0) {
@@ -250,16 +253,34 @@ int FdBroker::Send(const std::string& target_appid,
   body = g_variant_new("(s)", sender_appid);
   g_dbus_message_set_unix_fd_list(msg, fd_list.GetRaw());
   g_dbus_message_set_body(msg, body);
-  g_dbus_connection_send_message(DBusConnectionManager::GetInst().GetConnection(),
-                                 msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-                                 nullptr, &err);
-  if (err != nullptr) {
+  reply = g_dbus_connection_send_message_with_reply_sync(DBusConnectionManager::GetInst().GetConnection(),
+                                 msg, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 500,
+                                 nullptr, nullptr, &err);
+  if (reply == nullptr) {
     LOGE("No reply. error = %s", err->message);
     g_error_free(err);
     g_object_unref(msg);
     return -1;
   }
 
+  reply_body = g_dbus_message_get_body(reply);
+  if (reply_body == nullptr) {
+    LOGE("g_dbus_message_get_body() is failed");
+    g_object_unref(msg);
+    return -1;
+  }
+
+  g_variant_get(reply_body, "(i)", &ret);
+
+  if (ret != 0) {
+    LOGE("Access Denied[sender_appid : %s]", sender_appid);
+    g_object_unref(msg);
+    g_object_unref(reply);
+       return -1;
+  }
+
+  LOGD("[Reply : %d]", ret);
+
   int fd = sock_pair.Detach(SocketPair::SENDER);
   g_object_unref(msg);
 
@@ -303,9 +324,14 @@ void FdBroker::OnReceiveDbusMethod(GDBusConnection *conn,
     GVariant *parameters, GDBusMethodInvocation *invocation,
     gpointer user_data) {
   FdBroker* broker = static_cast<FdBroker*>(user_data);
+  int ret;
 
-  broker->ReceiveMessage(parameters, invocation);
-  g_dbus_method_invocation_return_value(invocation, nullptr);
+  AccessController& ac = broker->GetAccessController();
+  ret = ac.CheckPrivilege(conn, sender);
+  if (ret == 0)
+    broker->ReceiveMessage(parameters, invocation);
+
+  g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
 }
 
 int FdBroker::GetOwnerId(const std::string& interface_name) {
@@ -362,6 +388,7 @@ int FdBroker::RegisterDbusInterface(const std::string& port_name) {
     "'>"
     "  <method name='send_message'>"
     "    <arg type='s' name='sender_appid' direction='in'/>"
+    "    <arg type='i' name='response' direction='out'/>"
     "  </method>"
     "  </interface>"
     "</node>";
@@ -433,5 +460,9 @@ int FdBroker::Listen(IEventListener* ev, const std::string& port_name) {
   return 0;
 }
 
+AccessController& FdBroker::GetAccessController() {
+  return ac_;
+}
+
 }  // namespace internal
-}  // namespace rpc_port
\ No newline at end of file
+}  // namespace rpc_port
index 8ae7451..d1f31b7 100644 (file)
@@ -26,6 +26,8 @@
 #include <map>
 #include <memory>
 
+#include "ac-internal.h"
+
 namespace rpc_port {
 namespace internal {
 
@@ -45,6 +47,7 @@ class FdBroker {
 
   int Send(const std::string& target_appid, const std::string& port_name);
   int Listen(IEventListener* ev, const std::string& port_name);
+  AccessController& GetAccessController();
 
  private:
   class DBusConnectionManager {
@@ -137,6 +140,7 @@ class FdBroker {
   IEventListener* listener_ = nullptr;
   int registration_id_ = 0;
   bool mock_;
+  AccessController ac_;
 };
 
 }  // namespace internal
index 76db22f..9aebc14 100755 (executable)
@@ -271,6 +271,16 @@ RPC_API int rpc_port_stub_listen(rpc_port_stub_h h) {
   return 0;
 }
 
+RPC_API int rpc_port_stub_add_privilege(rpc_port_stub_h h,
+    const char* privilege) {
+  if (h == nullptr)
+    return -1;
+
+  auto p = static_cast<::StubExt*>(h);
+  p->AddPrivilege(privilege);
+  return 0;
+}
+
 RPC_API int rpc_port_stub_add_connected_event_cb(rpc_port_stub_h h,
     rpc_port_stub_connected_event_cb cb, void* data) {
   if (h == nullptr)
index 07c8497..a1b963f 100644 (file)
@@ -44,6 +44,11 @@ void Stub::Listen(IEventListener* ev) {
   fd_broker_.Listen(this, port_name_);
 }
 
+void Stub::AddPrivilege(const std::string& privilege) {
+  AccessController& ac = fd_broker_.GetAccessController();
+  ac.AddPrivilege(privilege);
+}
+
 gboolean Stub::OnDataReceived(GIOChannel *gio, GIOCondition cond,
                               gpointer data) {
   Stub* stub = static_cast<Stub*>(data);
@@ -143,4 +148,4 @@ int Stub::AcceptedPort::Watch() {
 }
 
 }  // namespace internal
-}  // namespace rpc_port
\ No newline at end of file
+}  // namespace rpc_port
index b6d8726..13a809b 100644 (file)
@@ -44,6 +44,7 @@ class Stub : private FdBroker::IEventListener {
   virtual ~Stub();
 
   void Listen(IEventListener* ev);
+  void AddPrivilege(const std::string& privilege);
 
  private:
   class AcceptedPort : public Port {
index b1002b2..f2dc9fc 100644 (file)
@@ -119,6 +119,10 @@ class RpcPortConnection : public RpcPortBase {
         }, this);
     ASSERT_EQ(ret, 0);
 
+    ret = rpc_port_stub_add_privilege(stub_handle_,
+        "http://tizen.org/privilege/appmanager.launch");
+    ASSERT_EQ(ret, 0);
+
     ret = rpc_port_stub_listen(stub_handle_);
     ASSERT_EQ(ret, 0);
   }