[Common] Implementation of security access checks.
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Tue, 17 Mar 2015 15:08:45 +0000 (16:08 +0100)
committerPawel Andruszkiewicz <p.andruszkie@samsung.com>
Thu, 19 Mar 2015 07:39:55 +0000 (16:39 +0900)
Change-Id: I7d0460d274e957487a6fa54a21f4caa73525f311

packaging/webapi-plugins.spec
src/common/common.gypi
src/common/extension.cc
src/common/extension.h

index eadd7c3dbe0adb10575ec32d0aa09973f86f2bd1..01d1a7f31ac12be23cf47b7fb1d626ffd4dc28f7 100755 (executable)
@@ -308,7 +308,7 @@ Tizen Web APIs implemented.
 %build
 
 export GYP_GENERATORS='ninja'
-GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=%{profile}"
+GYP_OPTIONS="--depth=. -Dtizen=1 -Dextension_build_type=Debug -Dextension_host_os=%{profile} -Dprivilege_engine=DB"
 GYP_OPTIONS="$GYP_OPTIONS -Ddisplay_type=x11"
 
 # feature flags
index d7698dffe6dd1242774aa1dc009187d33b598ca0..a8ac618844d4de159cc2a9363fbdd2fa7015cf8b 100644 (file)
             'dlog',
             'glib-2.0',
             'capi-appfw-app-manager',
-            'capi-appfw-package-manager'
+            'capi-appfw-package-manager',
           ]
         },
+        'conditions': [
+          ['privilege_engine == "DB"', {
+            'defines': ['PRIVILEGE_USE_DB'],
+            'variables': {
+              'packages': [
+                'sqlite3',
+              ],
+            },
+          }],
+          ['privilege_engine == "ACE"', {
+            'defines': ['PRIVILEGE_USE_ACE'],
+            'variables': {
+              'packages': [
+                'sqlite3',
+                'security-client',
+              ],
+            },
+          }],
+          ['privilege_engine == "CYNARA"', {
+            'defines': ['PRIVILEGE_USE_CYNARA'],
+            'variables': {
+              'packages': [
+              ],
+            },
+          }],
+        ],
       }, {
         'sources/': [['exclude', '_tizen\\.cc$|tizen/']],
         'includes/': [['exclude', '_tizen\\.gypi$|tizen/']],
index de14fd8e13b52da6b6ed73f214680541e93132e3..abd4cfb711a49f1fab7f934267a0048be32bb761 100644 (file)
 #include <string>
 #include <map>
 
+#ifdef PRIVILEGE_USE_DB
+#include <sqlite3.h>
+#elif PRIVILEGE_USE_ACE
+#include <sqlite3.h>
+#include <dpl/wrt-dao-ro/WrtDatabase.h>
+#include <ace_api_client.h>
+#elif PRIVILEGE_USE_CYNARA
+// TODO
+#endif
+
 #include "common/logger.h"
+#include "common/scope_exit.h"
 
 namespace {
 
@@ -342,6 +353,255 @@ void ReportError(const PlatformResult& error, picojson::object* out) {
   out->insert(std::make_pair("status", picojson::value("error")));
   out->insert(std::make_pair("error", error.ToJSON()));
 }
+
+namespace {
+
+#ifdef PRIVILEGE_USE_DB
+
+class AccessControlImpl {
+ public:
+  AccessControlImpl()
+      : initialized_(false) {
+    LoggerD("Privilege access checked using DB.");
+
+    const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
+    sqlite3* db = nullptr;
+
+    int ret = sqlite3_open(kWrtDBPath, &db);
+    if (SQLITE_OK != ret) {
+      LoggerE("Failed to access WRT database");
+      return;
+    }
+
+    const char* kQuery = "select name from WidgetFeature where app_id = "
+                         "(select app_id from WidgetInfo where tizen_appid = ?)"
+                         " and rejected = 0";
+    const std::string app_id = common::Extension::GetRuntimeVariable("app_id", 64);
+    sqlite3_stmt* stmt = nullptr;
+
+    ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
+    ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
+
+    SCOPE_EXIT {
+      sqlite3_finalize(stmt);
+      sqlite3_close(db);
+    };
+
+    if (SQLITE_OK != ret) {
+      LoggerE("Failed to query WRT database");
+      return;
+    }
+
+    while (sqlite3_step(stmt) == SQLITE_ROW) {
+      const char* privilege = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
+      SLoggerD("Granted: %s", privilege);
+      granted_privileges_.push_back(privilege);
+    }
+
+    initialized_ = true;
+  }
+
+  ~AccessControlImpl() {}
+
+  bool CheckAccess(const std::vector<std::string>& privileges) {
+    if (!initialized_) {
+      return false;
+    }
+
+    for (const auto& privilege : privileges) {
+      if (std::find(granted_privileges_.begin(), granted_privileges_.end(), privilege) == granted_privileges_.end()) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+ private:
+  bool initialized_;
+  std::vector<std::string> granted_privileges_;
+};
+
+#elif PRIVILEGE_USE_ACE
+
+class AccessControlImpl {
+ public:
+  AccessControlImpl()
+      : initialized_(false),
+        widget_id_(-1) {
+    LoggerD("Privilege access checked using ACE.");
+    // get widget ID
+    const char* kWrtDBPath = "/opt/dbspace/.wrt.db";
+    sqlite3* db = nullptr;
+
+    int ret = sqlite3_open(kWrtDBPath, &db);
+    if (SQLITE_OK != ret) {
+      LoggerE("Failed to access WRT database");
+      return;
+    }
+
+    const char* kQuery = "select app_id from WidgetInfo where tizen_appid = ?";
+    const std::string app_id = common::Extension::GetRuntimeVariable("app_id", 64);
+    sqlite3_stmt* stmt = nullptr;
+
+    ret = sqlite3_prepare_v2(db, kQuery, -1, &stmt, nullptr);
+    ret |= sqlite3_bind_text(stmt, 1, app_id.c_str(), -1, SQLITE_TRANSIENT);
+
+    SCOPE_EXIT {
+      sqlite3_finalize(stmt);
+      sqlite3_close(db);
+    };
+
+    if (SQLITE_OK != ret) {
+      LoggerE("Failed to query WRT database");
+      return;
+    }
+
+    if (sqlite3_step(stmt) == SQLITE_ROW) {
+      widget_id_ = sqlite3_column_int(stmt, 0);
+    } else {
+      LoggerE("Application %s not found.", app_id.c_str());
+      return;
+    }
+
+    // start ACE
+    if (ACE_OK != ace_client_initialize(AlwaysDeny)) {
+      LoggerE("Failed to initialize ACE.");
+    } else {
+      // in order to work, WrtDatabase needs to be bound to thread
+      // which is going to check the WrtAccess
+      WrtDB::WrtDatabase::attachToThreadRO();
+      // set the session ID
+      session_id_ = app_id + std::to_string(widget_id_);
+      // we're ready
+      initialized_ = true;
+    }
+  }
+
+  ~AccessControlImpl() {
+    if (initialized_) {
+      WrtDB::WrtDatabase::detachFromThread();
+      ace_client_shutdown();
+    }
+  }
+
+  bool CheckAccess(const std::vector<std::string>& privileges) {
+    if (!initialized_) {
+      return false;
+    }
+
+    ace_check_result_t result = ACE_PRIVILEGE_DENIED;
+    ace_request_t request;
+    const auto count = privileges.size();
+
+    request.session_id = const_cast<char*>(session_id_.c_str());
+    request.widget_handle = widget_id_;
+    request.feature_list = { 0, 0 };
+    request.dev_cap_list = { 0, 0 };
+
+    request.feature_list.count = count;
+    request.feature_list.items = new char*[count];
+
+    SCOPE_EXIT {
+      delete [] request.feature_list.items;
+    };
+
+    for (size_t i = 0; i < count; ++i) {
+      request.feature_list.items[i] = const_cast<char*>(privileges[i].c_str());
+    }
+
+    if (ACE_OK != ace_check_access_ex(&request, &result)) {
+      LoggerE("Failed to check privilege.");
+      return false;
+    } else {
+      return (result == ACE_ACCESS_GRANTED);
+    }
+  }
+
+ private:
+  static ace_return_t AlwaysDeny(ace_popup_t popup_type,
+                                 const ace_resource_t resource_name,
+                                 const ace_session_id_t session_id,
+                                 const ace_param_list_t* param_list,
+                                 ace_widget_handle_t handle,
+                                 ace_bool_t* validation_result) {
+    if (validation_result) {
+      *validation_result = ACE_TRUE;
+    }
+    return ACE_OK;
+  }
+
+  bool initialized_;
+  int widget_id_;
+  std::string session_id_;
+};
+
+#elif PRIVILEGE_USE_CYNARA
+
+class AccessControlImpl {
+ public:
+  AccessControlImpl() {
+    LoggerD("Privilege access checked using Cynara.");
+    // TODO
+  }
+
+  ~AccessControlImpl() {
+    // TODO
+  }
+
+  bool CheckAccess(const std::vector<std::string>& privileges) {
+    // TODO
+    return false;
+  }
+};
+
+#else
+
+class AccessControlImpl {
+ public:
+  AccessControlImpl() {
+    LoggerD("Privilege access - deny all.");
+  }
+
+  bool CheckAccess(const std::vector<std::string>& privileges) {
+    return false;
+  }
+};
+
+#endif
+
+class AccessControl {
+ public:
+  static AccessControl& GetInstance() {
+    static AccessControl instance;
+    return instance;
+  }
+
+  bool CheckAccess(const std::string& privilege) {
+    return CheckAccess(std::vector<std::string>{privilege});
+  }
+
+  bool CheckAccess(const std::vector<std::string>& privileges) {
+    return impl_.CheckAccess(privileges);
+  }
+
+ private:
+  AccessControl() {}
+  ~AccessControl() {}
+  AccessControlImpl impl_;
+};
+
+} // namespace
+
+PlatformResult CheckAccess(const std::string& privilege) {
+  if (AccessControl::GetInstance().CheckAccess(privilege)) {
+    return PlatformResult(ErrorCode::NO_ERROR);
+  } else {
+    LoggerD("Access to privilege: %s has been denied.", privilege.c_str());
+    return PlatformResult(ErrorCode::SECURITY_ERR, "Permission denied");
+  }
+}
+
 }  // namespace tools
 
 }  // namespace common
index 2396b6ad8a00b836504b12e3aee1ef1bd6325074..607a791cdf5f99e70d73315d2a30d3e94656bf79 100644 (file)
@@ -130,6 +130,18 @@ void ReportSuccess(const picojson::value& result, picojson::object& out);
 void ReportError(picojson::object& out);
 void ReportError(const PlatformException& ex, picojson::object& out);
 void ReportError(const PlatformResult& error, picojson::object* out);
+
+common::PlatformResult CheckAccess(const std::string& privilege);
+
+#define CHECK_PRIVILEGE_ACCESS(privilege, out) \
+do { \
+  auto r = common::tools::CheckAccess(privilege); \
+  if (!r) { \
+    common::tools::ReportError(r, out); \
+    return; \
+  } \
+} while (0)
+
 }  // namespace tools
 
 }  // namespace common