From d55b79da30a9edaa2baea1852ab4c9e28fbbc102 Mon Sep 17 00:00:00 2001 From: Sangwan Kwon Date: Thu, 14 Nov 2019 16:07:57 +0900 Subject: [PATCH] Add default admin as vist-cli Signed-off-by: Sangwan Kwon --- CMake/Macro.cmake | 6 +++++ packaging/vist.spec | 2 ++ src/CMakeLists.txt | 3 ++- src/vist/CMakeLists.txt | 18 ++++++++++++- src/vist/client/CMakeLists.txt | 14 ++++++++-- src/vist/client/tests/client.cpp | 14 ++++++---- src/vist/main/cli.cpp | 55 ++++++++++++++++++++++++++++++++++++++ src/vist/policy/policy-manager.cpp | 2 ++ src/vist/policy/policy-storage.cpp | 25 ++++++++++------- src/vist/policy/policy-storage.hpp | 2 +- src/vist/policy/tests/core.cpp | 2 +- src/vist/policy/tests/storage.cpp | 34 ++++++++++++++++------- 12 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 src/vist/main/cli.cpp diff --git a/CMake/Macro.cmake b/CMake/Macro.cmake index 4c0d54b..d7e804d 100644 --- a/CMake/Macro.cmake +++ b/CMake/Macro.cmake @@ -36,6 +36,12 @@ MACRO(ADD_VIST_LIBRARY TARGET) SET(${TARGET_VIST_LIB}_SRCS ${${TARGET_VIST_LIB}_SRCS} PARENT_SCOPE) ENDMACRO(ADD_VIST_LIBRARY) +MACRO(ADD_VIST_CLIENT_LIBRARY TARGET) + ADD_LIBRARY(${TARGET} OBJECT ${ARGN}) + LIST(APPEND ${TARGET_VIST_CLIENT_LIB}_SRCS $) + SET(${TARGET_VIST_LIB}_SRCS ${${TARGET_VIST_CLIENT_LIB}_SRCS} PARENT_SCOPE) +ENDMACRO(ADD_VIST_CLIENT_LIBRARY) + MACRO(ADD_VIST_POLICY_LIBRARY TARGET) ADD_LIBRARY(${TARGET} OBJECT ${ARGN}) LIST(APPEND ${TARGET_VIST_POLICY_LIB}_SRCS $) diff --git a/packaging/vist.spec b/packaging/vist.spec index e6b6027..e902ba2 100644 --- a/packaging/vist.spec +++ b/packaging/vist.spec @@ -70,6 +70,7 @@ cp %SOURCE1 . -DUSER_NAME=%{user_name} \ -DGROUP_NAME=%{group_name} \ -DSMACK_LABEL=%{smack_label} \ + -DDEFAULT_ADMIN_PATH=%{_bindir}/vist-cli \ -DDB_INSTALL_DIR:PATH=%{vist_db_dir} \ -DPLUGIN_INSTALL_DIR:PATH=%{vist_plugin_dir} \ -DSCRIPT_INSTALL_DIR:PATH=%{vist_script_dir} @@ -92,6 +93,7 @@ rm -rf %{buildroot} %license LICENSE-Apache-2.0 %license LICENSE-GPL-2.0 %license LICENSE-MIT +%{_bindir}/vist-cli %{_bindir}/vistd %{vist_script_dir}/*.sql %dir %attr(-, %{user_name}, %{group_name}) %{vist_db_dir} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 08d05f8..52f231e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,8 +13,9 @@ # limitations under the License SET(TARGET_OSQUERY_LIB osquery) -SET(TARGET_VIST_POLICY_LIB vist-policy) +SET(TARGET_VIST_CLIENT_LIB vist-client) SET(TARGET_VIST_LIB vist) +SET(TARGET_VIST_POLICY_LIB vist-policy) ADD_SUBDIRECTORY(osquery) diff --git a/src/vist/CMakeLists.txt b/src/vist/CMakeLists.txt index 26157a9..66bfde5 100644 --- a/src/vist/CMakeLists.txt +++ b/src/vist/CMakeLists.txt @@ -12,19 +12,21 @@ # See the License for the specific language governing permissions and # limitations under the License +SET(TARGET_VIST_CLI vist-cli) SET(TARGET_VIST_DAEMON vistd) SET(TARGET_VIST_TEST vist-test) SET(${TARGET_VIST_LIB}_SRCS "") SET(${TARGET_VIST_LIB}_TESTS "") -SET(DEPENDENCY klay dlog) +SET(DEPENDENCY klay dlog gflags) PKG_CHECK_MODULES(VIST_DEPS REQUIRED ${DEPENDENCY}) INCLUDE_DIRECTORIES(SYSTEM . common ${VIST_DEPS_INCLUDE_DIRS}) ADD_DEFINITIONS(-DDB_PATH="${DB_INSTALL_DIR}/.vist.db" + -DDEFAULT_ADMIN_PATH="${DEFAULT_ADMIN_PATH}" -DPLUGIN_INSTALL_DIR="${PLUGIN_INSTALL_DIR}" -DSCRIPT_INSTALL_DIR="${SCRIPT_INSTALL_DIR}") @@ -54,6 +56,20 @@ INSTALL(TARGETS ${TARGET_VIST_DAEMON} WORLD_READ WORLD_EXECUTE) +ADD_EXECUTABLE(${TARGET_VIST_CLI} main/cli.cpp) +TARGET_LINK_LIBRARIES(${TARGET_VIST_CLI} ${TARGET_VIST_CLIENT_LIB}) +SET_TARGET_PROPERTIES(${TARGET_VIST_CLI} PROPERTIES COMPILE_FLAGS "-fPIE") +SET_TARGET_PROPERTIES(${TARGET_VIST_CLI} PROPERTIES LINK_FLAGS "-pie") +INSTALL(TARGETS ${TARGET_VIST_CLI} + DESTINATION ${CMAKE_INSTALL_BINDIR} + PERMISSIONS OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE) + FILE(GLOB COMMON_TESTS "tests/*.cpp") ADD_VIST_TEST(${COMMON_TESTS}) diff --git a/src/vist/client/CMakeLists.txt b/src/vist/client/CMakeLists.txt index 8d893ab..cb38c21 100644 --- a/src/vist/client/CMakeLists.txt +++ b/src/vist/client/CMakeLists.txt @@ -12,8 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License -ADD_VIST_LIBRARY(vist_client query.cpp - virtual-table.cpp) +SET(${TARGET_VIST_CLIENT_LIB}_SRCS "") + +PKG_CHECK_MODULES(VIST_CLIENT_DEPS REQUIRED gflags klay dlog) + +INCLUDE_DIRECTORIES(SYSTEM . ${VIST_CLIENT_DEPS_INCLUDE_DIRS}) + +ADD_VIST_CLIENT_LIBRARY(vist_client query.cpp + virtual-table.cpp) FILE(GLOB CLIENT_TESTS "tests/*.cpp") ADD_VIST_TEST(${CLIENT_TESTS}) + +ADD_LIBRARY(${TARGET_VIST_CLIENT_LIB} STATIC ${${TARGET_VIST_CLIENT_LIB}_SRCS}) +TARGET_LINK_LIBRARIES(${TARGET_VIST_CLIENT_LIB} ${VIST_CLIENT_DEPS_LIBRARIES} + pthread) diff --git a/src/vist/client/tests/client.cpp b/src/vist/client/tests/client.cpp index e45c60b..f21bd66 100644 --- a/src/vist/client/tests/client.cpp +++ b/src/vist/client/tests/client.cpp @@ -32,23 +32,27 @@ TEST(ClientTests, query) { } TEST(ClientTests, admin_enrollment) { - auto rows = Query::Execute("INSERT INTO policy_admin (name) VALUES ('testAdmin')"); + /// Default policy admin is always exist. + auto rows = Query::Execute("SELECT * FROM policy_admin"); + EXPECT_EQ(rows.size(), 1); + + rows = Query::Execute("INSERT INTO policy_admin (name) VALUES ('testAdmin')"); EXPECT_EQ(rows.size(), 0); rows = Query::Execute("SELECT * FROM policy_admin"); - EXPECT_EQ(rows.size(), 1); + EXPECT_EQ(rows.size(), 2); Query::Execute("INSERT INTO policy_admin (name) VALUES ('testAdmin2')"); rows = Query::Execute("SELECT * FROM policy_admin"); - EXPECT_EQ(rows.size(), 2); + EXPECT_EQ(rows.size(), 3); rows = Query::Execute("DELETE FROM policy_admin WHERE name = 'testAdmin'"); EXPECT_EQ(rows.size(), 0); rows = Query::Execute("SELECT * FROM policy_admin"); - EXPECT_EQ(rows.size(), 1); + EXPECT_EQ(rows.size(), 2); Query::Execute("DELETE FROM policy_admin WHERE name = 'testAdmin2'"); rows = Query::Execute("SELECT * FROM policy_admin"); - EXPECT_EQ(rows.size(), 0); + EXPECT_EQ(rows.size(), 1); } diff --git a/src/vist/main/cli.cpp b/src/vist/main/cli.cpp new file mode 100644 index 0000000..e3d80a4 --- /dev/null +++ b/src/vist/main/cli.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 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 + */ + +#include +#include + +#include + +#include +#include +#include + +using namespace vist; + +DEFINE_string(query, "", "Query statement to execute."); + +int main(int argc, char *argv[]) try { + gflags::SetUsageMessage("ViST default admin program."); + gflags::ParseCommandLineFlags(&argc, &argv, true); + + if (!FLAGS_query.empty()) { + auto rows = Query::Execute(FLAGS_query); + + std::cout << "Success to query." << std::endl; + + for (const auto& row : rows) { + std::cout << "\tRow info >> "; + for (const auto& col : row) + std::cout << "Column[" << col.first << "] = " << col.second << ", "; + std::cout << std::endl; + } + + std::cout << "Total " << rows.size() << "-rows." << std::endl; + } + return EXIT_SUCCESS; +} catch(const Exception& e) { + std::cout << "Failed message: " << e.what() << std::endl; + return EXIT_FAILURE; +} catch(const std::exception& e) { + std::cout << "Failed message: " << e.what() << std::endl; + return EXIT_FAILURE; +} diff --git a/src/vist/policy/policy-manager.cpp b/src/vist/policy/policy-manager.cpp index 4dee112..6fbda6f 100644 --- a/src/vist/policy/policy-manager.cpp +++ b/src/vist/policy/policy-manager.cpp @@ -30,6 +30,8 @@ PolicyManager::PolicyManager() : storage(DB_PATH) loadProviders(PLUGIN_INSTALL_DIR); int cnt = loadPolicies(); INFO(VIST) << std::to_string(cnt) << "-policies loaded"; + + this->storage.enroll(DEFAULT_ADMIN_PATH); } std::pair PolicyManager::loadProviders(const std::string& path) diff --git a/src/vist/policy/policy-storage.cpp b/src/vist/policy/policy-storage.cpp index 3df7179..596d361 100644 --- a/src/vist/policy/policy-storage.cpp +++ b/src/vist/policy/policy-storage.cpp @@ -84,7 +84,7 @@ void PolicyStorage::syncPolicyDefinition() this->definitions.emplace(pd.name, std::move(pd)); } - DEBUG(VIST) << definitions.size() << "- policies synced."; + DEBUG(VIST) << definitions.size() << "-policies synced."; } void PolicyStorage::syncAdmin() @@ -113,7 +113,7 @@ void PolicyStorage::syncPolicyActivated() this->activatedPolicies.emplace(pa.policy, std::move(pa)); } - DEBUG(VIST) << activatedPolicies.size() << "- activated-policies synced."; + DEBUG(VIST) << activatedPolicies.size() << "-activated-policies synced."; } std::string PolicyStorage::getScript(const std::string& name) @@ -160,7 +160,6 @@ void PolicyStorage::enroll(const std::string& name) } std::string query = adminTable.insert(&Admin::name); - DEBUG(VIST) << "Enroll admin query statement: " << query; database::Statement stmt(*database, query); stmt.bind(1, name); if (!stmt.exec()) @@ -177,6 +176,9 @@ void PolicyStorage::enroll(const std::string& name) void PolicyStorage::disenroll(const std::string& name) { + if (name == DEFAULT_ADMIN_PATH) + THROW(ErrCode::RuntimeError) << "Cannot disenroll default admin."; + INFO(VIST) << "Disenroll admin: " << name; auto iter = std::find(admins.begin(), admins.end(), name); if (iter == admins.end()) { @@ -208,8 +210,8 @@ void PolicyStorage::update(const std::string& admin, int policyValue = value; std::string query = polActivatedTable.update(&PolicyActivated::value) - .where(expr(&PolicyActivated::admin) == admin && - expr(&PolicyActivated::policy) == policy); + .where(expr(&PolicyActivated::admin) == admin && + expr(&PolicyActivated::policy) == policy); database::Statement stmt(*database, query); stmt.bind(1, policyValue); stmt.bind(2, admin); @@ -220,6 +222,7 @@ void PolicyStorage::update(const std::string& admin, syncPolicyActivated(); } +/// TODO(sangwan.kwon) Re-design strictest logic PolicyValue PolicyStorage::strictest(const std::string& policy) { if (definitions.find(policy) == definitions.end()) @@ -232,19 +235,23 @@ PolicyValue PolicyStorage::strictest(const std::string& policy) std::shared_ptr strictestPtr = nullptr; auto range = activatedPolicies.equal_range(policy); for (auto iter = range.first; iter != range.second; iter++) { + DEBUG(VIST) << "Admin: " << iter->second.admin << ", " + << "Policy: " << iter->second.policy << ", " + << "Value: " << std::to_string(iter->second.value); + int value = iter->second.value; if (strictestPtr == nullptr) strictestPtr = std::make_shared(value); else - strictestPtr->value = (*strictestPtr < value) ? strictestPtr->value : value; - - DEBUG(VIST) << "The strictest of policy[" << policy - << "] : " + std::to_string(strictestPtr->value); + strictestPtr->value = (strictestPtr->value > value) ? strictestPtr->value : value; } if (strictestPtr == nullptr) THROW(ErrCode::RuntimeError) << "Not exist managed policy: " << policy; + DEBUG(VIST) << "The strictest value of [" << policy + << "] is " << std::to_string(strictestPtr->value); + return std::move(*strictestPtr); } diff --git a/src/vist/policy/policy-storage.hpp b/src/vist/policy/policy-storage.hpp index 4ef524d..938b90d 100644 --- a/src/vist/policy/policy-storage.hpp +++ b/src/vist/policy/policy-storage.hpp @@ -74,7 +74,7 @@ private: /// DB Cache objects /// TODO(Sangwan): add locking mechanism std::vector admins; - std::unordered_map activatedPolicies; + std::unordered_multimap activatedPolicies; std::unordered_map definitions; }; diff --git a/src/vist/policy/tests/core.cpp b/src/vist/policy/tests/core.cpp index c5c53d9..0a764d9 100644 --- a/src/vist/policy/tests/core.cpp +++ b/src/vist/policy/tests/core.cpp @@ -43,7 +43,7 @@ TEST_F(PolicyCoreTests, policy_set_get) { /// Manager should return the strongest policy. policy = manager.get("bluetooth"); - EXPECT_EQ(policy.value, 5); + EXPECT_EQ(policy.value, 10); manager.disenroll("testAdmin"); manager.disenroll("testAdmin1"); diff --git a/src/vist/policy/tests/storage.cpp b/src/vist/policy/tests/storage.cpp index 78fcc39..0268055 100644 --- a/src/vist/policy/tests/storage.cpp +++ b/src/vist/policy/tests/storage.cpp @@ -45,7 +45,7 @@ TEST_F(PolicyStorageTests, initialize) try { // DB is maden at run-time PolicyStorage storage("/tmp/dummy"); - } catch (const std::exception&) { + } catch (const std::exception& e) { isRaised = true; } @@ -55,7 +55,8 @@ TEST_F(PolicyStorageTests, initialize) TEST_F(PolicyStorageTests, enrollment) { auto storage = getStorage(); - EXPECT_FALSE(storage->isActivated()); + /// Since default admin exists, storage is always activated. + EXPECT_TRUE(storage->isActivated()); storage->enroll("testAdmin0"); storage->enroll("testAdmin1"); @@ -65,7 +66,7 @@ TEST_F(PolicyStorageTests, enrollment) EXPECT_TRUE(storage->isActivated()); storage->disenroll("testAdmin1"); - EXPECT_FALSE(storage->isActivated()); + EXPECT_TRUE(storage->isActivated()); } TEST_F(PolicyStorageTests, update) @@ -117,7 +118,7 @@ TEST_F(PolicyStorageTests, strictest) EXPECT_TRUE(isRaised); auto policy = storage->strictest("bluetooth"); - EXPECT_EQ(policy.value, 3); + EXPECT_EQ(policy.value, 6); storage->disenroll("testAdmin0"); storage->disenroll("testAdmin1"); @@ -139,21 +140,36 @@ TEST_F(PolicyStorageTests, admin_list) auto storage = getStorage(); auto admins = storage->getAdmins(); - EXPECT_EQ(admins.size(), 0); + EXPECT_EQ(admins.size(), 1); storage->enroll("testAdmin1"); admins = storage->getAdmins(); - EXPECT_EQ(admins.size(), 1); + EXPECT_EQ(admins.size(), 2); storage->enroll("testAdmin2"); admins = storage->getAdmins(); - EXPECT_EQ(admins.size(), 2); + EXPECT_EQ(admins.size(), 3); storage->disenroll("testAdmin2"); admins = storage->getAdmins(); - EXPECT_EQ(admins.size(), 1); + EXPECT_EQ(admins.size(), 2); storage->disenroll("testAdmin1"); admins = storage->getAdmins(); - EXPECT_EQ(admins.size(), 0); + EXPECT_EQ(admins.size(), 1); +} + +TEST_F(PolicyStorageTests, default_admin) +{ + auto storage = getStorage(); + bool isRaised = false; + + /// Cannot disenroll default admin + try { + storage->disenroll(DEFAULT_ADMIN_PATH); + } catch (const std::exception& e) { + isRaised = true; + } + + EXPECT_TRUE(isRaised); } -- 2.7.4