Redesign policy management logic 70/238770/2
authorSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 17 Jul 2020 06:22:20 +0000 (15:22 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 17 Jul 2020 07:08:21 +0000 (16:08 +0900)
[AS-IS]
- Policy Schema: Struct-based schema
- Policy Provider: Plugin Loader
- Policy Management: Virtual Table (static)

[TO-BE]
- Policy Schema: Struct-based schema
- Policy Provider & Management: Dynamic Virtual Table

Change-Id: I705ffee9e0d3368ac187c5498bd102f8d942a7d8
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
22 files changed:
CMake/Definition.cmake
CMakeLists.txt
packaging/vist.spec
src/vist/CMakeLists.txt
src/vist/common/dynamic-loader.cpp
src/vist/policy/api.cpp
src/vist/policy/api.hpp
src/vist/policy/policy-manager.cpp
src/vist/policy/policy-manager.hpp
src/vist/policy/tests/core.cpp
src/vist/service/tests/core.cpp
src/vist/service/vistd.cpp
src/vist/service/vistd.hpp
src/vist/table/CMakeLists.txt
src/vist/table/dynamic-table.hpp [moved from src/vist/table/bluetooth.hpp with 74% similarity]
src/vist/table/policy/policy-admin.cpp [moved from src/vist/table/policy-admin.cpp with 100% similarity]
src/vist/table/policy/policy-admin.hpp [moved from src/vist/table/policy-admin.hpp with 100% similarity]
src/vist/table/policy/policy.cpp [moved from src/vist/table/policy.cpp with 100% similarity]
src/vist/table/policy/policy.hpp [moved from src/vist/table/policy.hpp with 100% similarity]
src/vist/table/policy/sample/CMakeLists.txt [moved from plugins/CMakeLists.txt with 58% similarity]
src/vist/table/policy/sample/sample.cpp [moved from src/vist/table/bluetooth.cpp with 52% similarity]
src/vist/table/policy/sample/sample.hpp [new file with mode: 0644]

index a210f32..52bfa5a 100644 (file)
@@ -25,12 +25,14 @@ SET(VIST_RW_DIR "${RW_DIR}/vist")
 
 SET(VIST_DB_DIR     "${VIST_RW_DIR}/db")
 SET(VIST_PLUGIN_DIR "${VIST_RO_DIR}/plugin")
+SET(VIST_TABLE_DIR  "${VIST_RO_DIR}/table")
 SET(VIST_SCRIPT_DIR "${VIST_RO_DIR}/script")
 
 SET(DEFAULT_POLICY_ADMIN "vist-cli")
-SET(DB_INSTALL_DIR     "${VIST_DB_DIR}")
-SET(PLUGIN_INSTALL_DIR "${VIST_PLUGIN_DIR}")
-SET(SCRIPT_INSTALL_DIR "${VIST_SCRIPT_DIR}")
+SET(DB_INSTALL_DIR       "${VIST_DB_DIR}")
+SET(PLUGIN_INSTALL_DIR   "${VIST_PLUGIN_DIR}")
+SET(TABLE_INSTALL_DIR    "${VIST_TABLE_DIR}")
+SET(SCRIPT_INSTALL_DIR   "${VIST_SCRIPT_DIR}")
 
 EXECUTE_PROCESS(COMMAND mkdir -p "${VIST_DB_DIR}")
 EXECUTE_PROCESS(COMMAND mkdir -p "${VIST_PLUGIN_DIR}")
index 5714bc4..995e690 100644 (file)
@@ -28,6 +28,11 @@ IF(NOT CMAKE_BUILD_TYPE)
        SET(CMAKE_BUILD_TYPE "DEBUG")
 ENDIF(NOT CMAKE_BUILD_TYPE)
 
+message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+message("CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+
 SET(CMAKE_CXX_FLAGS_DEBUG   "-g -std=c++1z -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
 SET(CMAKE_CXX_FLAGS_RELEASE "-g -std=c++1z -O2 -DNDEBUG")
 
@@ -45,7 +50,6 @@ ENABLE_TESTING()
 
 ADD_SUBDIRECTORY(data)
 ADD_SUBDIRECTORY(src)
-ADD_SUBDIRECTORY(plugins)
 
 IF(DEFINED GBS_BUILD)
        ADD_SUBDIRECTORY(systemd)
index 535d8f0..e28e684 100644 (file)
@@ -38,6 +38,7 @@ Requires: libsystemd
 
 %global vist_db_dir     %{vist_rw_dir}/db
 %global vist_plugin_dir %{vist_ro_dir}/plugin
+%global vist_table_dir %{vist_ro_dir}/table
 %global vist_script_dir %{vist_ro_dir}/script
 
 %description
@@ -67,6 +68,7 @@ cp %SOURCE1 .
                 -DDEFAULT_POLICY_ADMIN=vist-cli \
                 -DDB_INSTALL_DIR:PATH=%{vist_db_dir} \
                 -DPLUGIN_INSTALL_DIR:PATH=%{vist_plugin_dir} \
+                -DTABLE_INSTALL_DIR:PATH=%{vist_table_dir} \
                 -DSCRIPT_INSTALL_DIR:PATH=%{vist_script_dir} \
                 -DSYSTEMD_UNIT_DIR:PATH=%{_unitdir}
 
index 6bd80e7..b96f0e4 100644 (file)
@@ -35,6 +35,7 @@ INCLUDE_DIRECTORIES(SYSTEM . common ${VIST_COMMON_DEPS_INCLUDE_DIRS})
 ADD_DEFINITIONS(-DDB_PATH="${DB_INSTALL_DIR}/.vist.db"
                                -DDEFAULT_POLICY_ADMIN="${DEFAULT_POLICY_ADMIN}"
                                -DPLUGIN_INSTALL_DIR="${PLUGIN_INSTALL_DIR}"
+                               -DTABLE_INSTALL_DIR="${TABLE_INSTALL_DIR}"
                                -DSCRIPT_INSTALL_DIR="${SCRIPT_INSTALL_DIR}")
 
 ADD_DEFINITIONS("-Werror")
index 92a7177..11113ba 100644 (file)
@@ -39,11 +39,14 @@ DynamicLoader::ScopedHandle DynamicLoader::init(const std::string& path, int fla
                return handle;
        };
 
-       auto close = [&](void* handle) {
+       auto close = [&](void* /*handle*/) {
                ::dlerror();
 
-               if (::dlclose(handle) != 0)
-                       THROW(ErrCode::RuntimeError) << "Failed to close library: " << ::dlerror();
+// Calling symbol & code after dlclose() makes SEGFAULT.
+// TODO: Sync dynamic loading's life-cycle with program.
+//
+//             if (::dlclose(handle) != 0)
+//                     THROW(ErrCode::RuntimeError) << "Failed to close library: " << ::dlerror();
        };
 
        return ScopedHandle(open(), close);
index 98e6b6b..90ae565 100644 (file)
@@ -56,6 +56,11 @@ void API::Admin::Disenroll(const std::string& admin)
        PolicyManager::Instance().disenroll(admin);
 }
 
+void API::Admin::AddProvider(std::shared_ptr<PolicyProvider>&& provider)
+{
+       PolicyManager::Instance().addProvider(std::move(provider));
+}
+
 void API::Admin::Activate(const std::string& admin, bool state)
 {
        PolicyManager::Instance().activate(admin, state);
index 2998c1f..80b03f2 100644 (file)
 
 #pragma once
 
+#include <vist/sdk/policy-provider.hpp>
 #include <vist/sdk/policy-value.hpp>
 
+#include <memory>
 #include <string>
 #include <unordered_map>
 
@@ -37,6 +39,8 @@ struct API {
                static void Activate(const std::string& admin, bool state = true);
                static bool IsActivated();
 
+               static void AddProvider(std::shared_ptr<PolicyProvider>&& provider);
+
                static std::unordered_map<std::string, int> GetAll();
        };
 };
index 7a63afb..8a67a35 100644 (file)
@@ -32,8 +32,6 @@ PolicyManager::PolicyManager() : storage(DB_PATH)
        loadProviders(PLUGIN_INSTALL_DIR);
        int cnt = loadPolicies();
        INFO(VIST) << std::to_string(cnt) << "-policies loaded";
-
-       this->storage.enroll(DEFAULT_POLICY_ADMIN);
 }
 
 std::pair<int, int> PolicyManager::loadProviders(const std::string& path)
@@ -75,6 +73,27 @@ std::pair<int, int> PolicyManager::loadProviders(const std::string& path)
        return std::make_pair(passed, failed);
 }
 
+void PolicyManager::addProvider(std::shared_ptr<PolicyProvider>&& provider)
+{
+       for (const auto& p : this->providers) {
+               if (p->getName() == provider->getName()) {
+                       INFO(VIST) << "Previous added provider: " << provider->getName();
+                       return;
+               }
+       }
+
+       for (const auto& [name, policy] : provider->policies) {
+               this->policies[name] = provider->getName();
+
+               if (!storage.exists(name))
+                       storage.define(name, policy->getInitial());
+       }
+
+       INFO(VIST) << "Added " << provider->policies.size()
+                          << "-policies from " << provider->getName();
+       this->providers.emplace_back(std::move(provider));
+}
+
 int PolicyManager::loadPolicies()
 {
        /// Make policy-provider map for performance
@@ -151,7 +170,7 @@ const std::shared_ptr<PolicyModel>& PolicyManager::getPolicy(const std::string&
 
        auto provider = this->policies[name];
        auto iter = std::find_if(this->providers.begin(), this->providers.end(),
-       [&provider](const std::unique_ptr<PolicyProvider>& p) {
+       [&provider](const std::shared_ptr<PolicyProvider>& p) {
                return p->getName() == provider;
        });
        if (iter == this->providers.end())
index 3eda4d7..ea46d94 100644 (file)
@@ -51,6 +51,8 @@ public:
        void activate(const std::string& admin, bool state);
        bool isActivated();
 
+       void addProvider(std::shared_ptr<PolicyProvider>&& provider);
+
        void set(const std::string& policy,
                         const PolicyValue& value,
                         const std::string& admin);
@@ -67,7 +69,7 @@ private:
        int loadPolicies();
 
        PolicyStorage storage;
-       std::vector<std::unique_ptr<PolicyProvider>> providers;
+       std::vector<std::shared_ptr<PolicyProvider>> providers;
 
        const std::shared_ptr<PolicyModel>& getPolicy(const std::string& name);
 
index 083ea95..98b5d5b 100644 (file)
@@ -33,17 +33,17 @@ TEST(PolicyCoreTests, policy_set_get_int)
 {
        auto& manager = PolicyManager::Instance();
        manager.enroll("testAdmin");
-       manager.set("sample-int-policy", PolicyValue(5), "testAdmin");
+       manager.set("sample_int_policy", PolicyValue(5), "testAdmin");
 
        /// Default Admin's policy is more strict. (Because of initial value: 7)
-       auto policy = manager.get("sample-int-policy");
+       auto policy = manager.get("sample_int_policy");
        EXPECT_EQ(static_cast<int>(policy), 7);
 
        manager.enroll("testAdmin1");
-       manager.set("sample-int-policy", PolicyValue(10), "testAdmin1");
+       manager.set("sample_int_policy", PolicyValue(10), "testAdmin1");
 
        /// Manager should return the strongest policy.
-       policy = manager.get("sample-int-policy");
+       policy = manager.get("sample_int_policy");
        EXPECT_EQ(static_cast<int>(policy), 10);
 
        manager.disenroll("testAdmin");
@@ -80,8 +80,8 @@ TEST(PolicyCoreTests, policy_get_all)
 TEST(PolicyCoreTests, policy_get_policy)
 {
        auto& manager = PolicyManager::Instance();
-       const auto& policy = manager.getPolicy("sample-int-policy");
-       EXPECT_EQ(policy->getName(), "sample-int-policy");
+       const auto& policy = manager.getPolicy("sample_int_policy");
+       EXPECT_EQ(policy->getName(), "sample_int_policy");
 
        bool raised = false;
        try {
index 83d6f73..7b5c505 100644 (file)
@@ -32,27 +32,29 @@ TEST_F(CoreTests, query_select)
 
        EXPECT_TRUE(rows.size() > 0);
 
-       std::string statement = "SELECT * FROM policy WHERE name = 'sample-int-policy'";
+       std::string statement = "SELECT * FROM policy WHERE name = 'sample_int_policy'";
        rows = Vistd::Query(statement);
 
-       EXPECT_EQ(rows.size(), 1);
-       EXPECT_EQ(rows[0]["name"], "sample-int-policy");
+       if (rows.size() == 1)
+               EXPECT_EQ(rows[0]["name"], "sample_int_policy");
+       else
+               EXPECT_TRUE(false);
 }
 
 TEST_F(CoreTests, query_update)
 {
        policy::API::Admin::Enroll("vist-test");
 
-       std::string statement = "SELECT * FROM policy WHERE name = 'sample-int-policy'";
+       std::string statement = "SELECT * FROM policy WHERE name = 'sample_int_policy'";
        auto rows = Vistd::Query(statement);
        /// Initial policy value
        EXPECT_EQ(rows[0]["value"], "I/7");
 
-       statement = "UPDATE policy SET value = 'I/10' WHERE name = 'sample-int-policy'";
+       statement = "UPDATE policy SET value = 'I/10' WHERE name = 'sample_int_policy'";
        rows = Vistd::Query(statement);
        EXPECT_EQ(rows.size(), 0);
 
-       statement = "SELECT * FROM policy WHERE name = 'sample-int-policy'";
+       statement = "SELECT * FROM policy WHERE name = 'sample_int_policy'";
        rows = Vistd::Query(statement);
        EXPECT_EQ(rows[0]["value"], "I/10");
 
index 695dc53..c2fffbb 100644 (file)
 
 #include "vistd.hpp"
 
+#include <vist/dynamic-loader.hpp>
 #include <vist/exception.hpp>
 #include <vist/logger.hpp>
+#include <vist/policy/api.hpp>
 #include <vist/policy/policy-manager.hpp>
 #include <vist/rmi/gateway.hpp>
 
-#include <vist/table/bluetooth.hpp>
-#include <vist/table/policy-admin.hpp>
-#include <vist/table/policy.hpp>
+#include <vist/table/dynamic-table.hpp>
+#include <vist/table/policy/policy-admin.hpp>
+#include <vist/table/policy/policy.hpp>
 
 #include <osquery/registry_interface.h>
 #include <osquery/sql.h>
 
+#include <filesystem>
+
 namespace {
 const std::string SOCK_ADDR = "/tmp/.vist";
 } // anonymous namespace
@@ -38,9 +42,10 @@ Vistd::Vistd()
 {
        osquery::registryAndPluginInit();
 
-       table::BluetoothTable::Init();
-       table::PolicyAdminTable::Init();
-       table::PolicyTable::Init();
+       this->loadStaticTable();
+       this->loadDynamicTable();
+
+       policy::API::Admin::Enroll(DEFAULT_POLICY_ADMIN);
 }
 
 void Vistd::start()
@@ -71,6 +76,7 @@ void Vistd::start()
 
 Rows Vistd::query(const std::string& statement)
 {
+       DEBUG(VIST) << "Excute query: " << statement;
        osquery::SQL sql(statement, true);
        if (!sql.ok())
                THROW(ErrCode::RuntimeError) << "Faild to execute query: " << sql.getMessageString();
@@ -78,4 +84,25 @@ Rows Vistd::query(const std::string& statement)
        return sql.rows();
 }
 
+void Vistd::loadStaticTable()
+{
+       table::PolicyAdminTable::Init();
+       table::PolicyTable::Init();
+}
+
+void Vistd::loadDynamicTable()
+{
+       for (auto& iter : std::filesystem::directory_iterator(TABLE_INSTALL_DIR)) {
+               DEBUG(VIST) << "Load dynamic table: " << iter.path();
+               DynamicLoader loader(iter.path());
+               auto factory = loader.load<table::DynamicTable::FactoryType>("DynamicTableFactory");
+               if (auto table = (*factory)(); table != nullptr) {
+                       table->init();
+                       delete table;
+               } else {
+                       ERROR(VIST) << "Failed to load table.";
+               }
+       }
+}
+
 } // namespace vist
index 818684a..87c5162 100644 (file)
@@ -58,6 +58,9 @@ private:
        ~Vistd() = default;
 
        void start();
+
+       void loadStaticTable();
+       void loadDynamicTable();
 };
 
 } // namespace vist
index 77e5f50..f05ce01 100644 (file)
@@ -12,6 +12,9 @@
 #  See the License for the specific language governing permissions and
 #  limitations under the License
 
-ADD_VIST_LIBRARY(vist_table bluetooth.cpp
-                                                       policy-admin.cpp
-                                                       policy.cpp)
+## static virtual table
+ADD_VIST_LIBRARY(vist_table policy/policy-admin.cpp
+                                                       policy/policy.cpp)
+
+## dynamic virtual table
+ADD_SUBDIRECTORY(policy/sample)
similarity index 74%
rename from src/vist/table/bluetooth.hpp
rename to src/vist/table/dynamic-table.hpp
index 883468a..b04de07 100644 (file)
 namespace vist {
 namespace table {
 
-using namespace osquery;
-
-class BluetoothTable final : public TablePlugin {
+class DynamicTable : public osquery::TablePlugin {
 public:
-       static void Init();
+       using FactoryType = DynamicTable* (*)();
 
-private:
-       TableColumns columns() const override;
-       TableRows generate(QueryContext&) override;
-       QueryData update(QueryContext&, const PluginRequest& request) override;
+       virtual void init() = 0;
 };
 
 } // namespace table
similarity index 58%
rename from plugins/CMakeLists.txt
rename to src/vist/table/policy/sample/CMakeLists.txt
index 09d1fe8..d97eea6 100644 (file)
@@ -1,10 +1,10 @@
-# Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2019-present 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
+# 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,
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+SET(TARGET "vist-plugin-sample")
 
-SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,noexecstack")
+INCLUDE_DIRECTORIES(SYSTEM)
 
-ADD_SUBDIRECTORY(sample)
+ADD_LIBRARY(${TARGET} SHARED sample.cpp)
+TARGET_LINK_LIBRARIES(${TARGET} vist-common ${TARGET_VIST_POLICY_LIB})
 
-IF(DEFINED GBS_BUILD)
-       ADD_SUBDIRECTORY(bluetooth)
-       ADD_SUBDIRECTORY(wifi)
-ENDIF(DEFINED GBS_BUILD)
+INSTALL(TARGETS ${TARGET} DESTINATION ${TABLE_INSTALL_DIR})
similarity index 52%
rename from src/vist/table/bluetooth.cpp
rename to src/vist/table/policy/sample/sample.cpp
index 25cf78f..f5d02a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2020-present Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2019-present 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.
  *  limitations under the License
  */
 
-#include "bluetooth.hpp"
+#include "sample.hpp"
+
+#include <vist/sdk/policy-model.hpp>
+#include <vist/sdk/policy-value.hpp>
+#include <vist/sdk/policy-provider.hpp>
 
-#include <vist/exception.hpp>
-#include <vist/json.hpp>
 #include <vist/logger.hpp>
 #include <vist/policy/api.hpp>
 
 #include <osquery/registry.h>
 #include <osquery/sql/dynamic_table_row.h>
 
-#include <memory>
-#include <stdexcept>
-#include <string>
+extern "C" vist::table::DynamicTable* DynamicTableFactory()
+{
+       return new vist::table::SamplePolicyTable;
+}
 
 namespace vist {
 namespace table {
 
-namespace {
+using namespace osquery;
 
-std::map<std::string, std::string> ALIAS = {
-       { "state", "bluetooth" },
-       { "desktopConnectivity", "bluetooth-desktop-connectivity" },
-       { "pairing", "bluetooth-pairing" },
-       { "tethering", "bluetooth-tethering"}
-};
-
-void setPolicy(const std::string& name, int value)
+void SamplePolicyTable::init()
 {
-       vist::policy::API::Admin::Set(name, vist::policy::PolicyValue(value));
-}
+       // Register virtual table to sqlite3
+       auto tables = RegistryFactory::get().registry("table");
+       tables->add("sample_policy", std::make_shared<SamplePolicyTable>());
 
-} // anonymous namespace
+       // Register policy to policy-manager
+       auto provider = std::make_shared<policy::Sample>("sample-provider");
+       provider->add(std::make_shared<policy::SampleIntPolicy>());
+       provider->add(std::make_shared<policy::SampleStrPolicy>());
 
-void BluetoothTable::Init()
-{
-       auto tables = RegistryFactory::get().registry("table");
-       tables->add("bluetooth", std::make_shared<BluetoothTable>());
+       policy::API::Admin::AddProvider(std::move(provider));
+
+       INFO(VIST_PLUGIN) << "Sample plugin loaded.";
 }
 
-TableColumns BluetoothTable::columns() const
+TableColumns SamplePolicyTable::columns() const
 {
        return {
-               std::make_tuple("state", INTEGER_TYPE, ColumnOptions::DEFAULT),
-               std::make_tuple("desktopConnectivity", INTEGER_TYPE, ColumnOptions::DEFAULT),
-               std::make_tuple("pairing", INTEGER_TYPE, ColumnOptions::DEFAULT),
-               std::make_tuple("tethering", INTEGER_TYPE, ColumnOptions::DEFAULT),
+               std::make_tuple("sample_int_policy", INTEGER_TYPE, ColumnOptions::DEFAULT),
+               std::make_tuple("sample_str_policy", TEXT_TYPE, ColumnOptions::DEFAULT),
        };
 }
 
-TableRows BluetoothTable::generate(QueryContext&) try
+TableRows SamplePolicyTable::generate(QueryContext&) try
 {
-       INFO(VIST) << "Select query about bluetooth table.";
-
-       QueryData results;
+       INFO(VIST) << "Select query about sample-policy table.";
 
        Row row;
+       int intPolicy = vist::policy::API::Get("sample_int_policy");
+       row["sample_int_policy"] = std::to_string(intPolicy);
 
-       for (const auto&[schemaName, policyName] : ALIAS) {
-               int value = vist::policy::API::Get(policyName);
-               row[schemaName] = std::to_string(value);
-       }
+       std::string strPolicy = vist::policy::API::Get("sample_str_policy");
+       row["sample_str_policy"] = strPolicy;
 
+       QueryData results;
        results.emplace_back(std::move(row));
 
        return osquery::tableRowsFromQueryData(std::move(results));
@@ -91,23 +87,22 @@ TableRows BluetoothTable::generate(QueryContext&) try
        return osquery::tableRowsFromQueryData({ r });
 }
 
-QueryData BluetoothTable::update(QueryContext&, const PluginRequest& request) try
+QueryData SamplePolicyTable::update(QueryContext&, const PluginRequest& request) try
 {
-       INFO(VIST) << "Update query about bluetooth table.";
+       INFO(VIST) << "Update query about sample-policy table.";
        if (request.count("json_values") == 0)
                throw std::runtime_error("Wrong request format. Not found json value.");
 
        DEBUG(VIST) << "Request values: " << request.at("json_values");
        json::Json document = json::Json::Parse(request.at("json_values"));
        json::Array values = document.get<json::Array>("values");
-       if (values.size() != 4)
+       if (values.size() != 2)
                throw std::runtime_error("Wrong request format.");
 
-       /// TODO(Sangwan): Sync vtab schema with policy definition
-       setPolicy("bluetooth", static_cast<int>(values.at(0)));
-       setPolicy("bluetooth-desktop-connectivity", static_cast<int>(values.at(1)));
-       setPolicy("bluetooth-pairing", static_cast<int>(values.at(2)));
-       setPolicy("bluetooth-tethering", static_cast<int>(values.at(3)));
+       policy::API::Admin::Set("sample_int_policy",
+                       policy::PolicyValue(static_cast<int>(values.at(0))));
+       policy::API::Admin::Set("sample_str_policy",
+                       policy::PolicyValue(static_cast<std::string>(values.at(1))));
 
        Row r;
        r["status"] = "success";
diff --git a/src/vist/table/policy/sample/sample.hpp b/src/vist/table/policy/sample/sample.hpp
new file mode 100644 (file)
index 0000000..3b241f5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (c) 2020-present 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
+ */
+/*
+ * Query example
+ * - SELECT * FROM sample_policy
+ * - UPDATE sample_policy SET sample_int_policy = 99
+ * - UPDATE sample_policy SET sample_str_policy = 'TEST_VALUE'
+ */
+
+#include <vist/logger.hpp>
+#include <vist/table/dynamic-table.hpp>
+
+#include <vist/sdk/policy-model.hpp>
+#include <vist/sdk/policy-provider.hpp>
+#include <vist/sdk/policy-value.hpp>
+
+#include <osquery/tables.h>
+
+#include <memory>
+#include <string>
+
+namespace vist {
+namespace policy {
+
+class SampleIntPolicy : public PolicyModel {
+public:
+       SampleIntPolicy() : PolicyModel("sample_int_policy", PolicyValue(7))
+       {
+       }
+
+       void onChanged(const PolicyValue& value) override
+       {
+               INFO(VIST_PLUGIN) << "sample_int_policy is changed to "
+                                                 << static_cast<int>(value);
+       }
+};
+
+class SampleStrPolicy : public PolicyModel {
+public:
+       SampleStrPolicy() : PolicyModel("sample_str_policy", PolicyValue("TEST"))
+       {
+       }
+
+       void onChanged(const PolicyValue& value) override
+       {
+               INFO(VIST_PLUGIN) << "sample_str_policy is changed to "
+                                                 << static_cast<std::string>(value);
+       }
+
+       int compare(const PolicyValue& lhs, const PolicyValue& rhs) const override
+       {
+               std::string lvalue = lhs;
+               std::string rvalue = rhs;
+
+               INFO(VIST_PLUGIN) << "Custom compare method is called with [" << lvalue
+                                                 << "], [" << rvalue << "]";
+
+               return lvalue.compare(rvalue);
+       }
+};
+
+class Sample : public PolicyProvider {
+public:
+       Sample(const std::string& name) : PolicyProvider(name)
+       {
+       }
+
+       ~Sample()
+       {
+       }
+};
+} // namespace policy
+
+namespace table {
+
+using namespace osquery;
+
+class SamplePolicyTable final : public DynamicTable {
+public:
+       void init();
+
+private:
+       TableColumns columns() const override;
+       TableRows generate(QueryContext&) override;
+       QueryData update(QueryContext&, const PluginRequest& request) override;
+};
+
+} // namespace table
+} // namespace vist