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}")
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")
ADD_SUBDIRECTORY(data)
ADD_SUBDIRECTORY(src)
-ADD_SUBDIRECTORY(plugins)
IF(DEFINED GBS_BUILD)
ADD_SUBDIRECTORY(systemd)
%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
-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}
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")
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);
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);
#pragma once
+#include <vist/sdk/policy-provider.hpp>
#include <vist/sdk/policy-value.hpp>
+#include <memory>
#include <string>
#include <unordered_map>
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();
};
};
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)
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
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())
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);
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);
{
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");
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 {
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");
#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
{
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()
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();
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
~Vistd() = default;
void start();
+
+ void loadStaticTable();
+ void loadDynamicTable();
};
} // namespace vist
# 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)
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
-# 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})
/*
- * 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));
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";
--- /dev/null
+/*
+ * 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