Add default admin as vist-cli
authorSangwan Kwon <sangwan.kwon@samsung.com>
Thu, 14 Nov 2019 07:07:57 +0000 (16:07 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Fri, 15 Nov 2019 06:01:41 +0000 (15:01 +0900)
Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
12 files changed:
CMake/Macro.cmake
packaging/vist.spec
src/CMakeLists.txt
src/vist/CMakeLists.txt
src/vist/client/CMakeLists.txt
src/vist/client/tests/client.cpp
src/vist/main/cli.cpp [new file with mode: 0644]
src/vist/policy/policy-manager.cpp
src/vist/policy/policy-storage.cpp
src/vist/policy/policy-storage.hpp
src/vist/policy/tests/core.cpp
src/vist/policy/tests/storage.cpp

index 4c0d54b..d7e804d 100644 (file)
@@ -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 $<TARGET_OBJECTS:${TARGET}>)
+       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 $<TARGET_OBJECTS:${TARGET}>)
index e6b6027..e902ba2 100644 (file)
@@ -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}
index 08d05f8..52f231e 100644 (file)
@@ -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)
 
index 26157a9..66bfde5 100644 (file)
 #  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})
 
index 8d893ab..cb38c21 100644 (file)
 #  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)
index e45c60b..f21bd66 100644 (file)
@@ -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 (file)
index 0000000..e3d80a4
--- /dev/null
@@ -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 <vist/client/query.hpp>
+#include <vist/exception.hpp>
+
+#include <gflags/gflags.h>
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+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<ErrCode>& 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;
+}
index 4dee112..6fbda6f 100644 (file)
@@ -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<int, int> PolicyManager::loadProviders(const std::string& path)
index 3df7179..596d361 100644 (file)
@@ -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<PolicyValue> 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<PolicyValue>(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);
 }
 
index 4ef524d..938b90d 100644 (file)
@@ -74,7 +74,7 @@ private:
        /// DB Cache objects
        /// TODO(Sangwan): add locking mechanism
        std::vector<std::string> admins;
-       std::unordered_map<std::string, PolicyActivated> activatedPolicies;
+       std::unordered_multimap<std::string, PolicyActivated> activatedPolicies;
        std::unordered_map<std::string, PolicyDefinition> definitions;
 };
 
index c5c53d9..0a764d9 100644 (file)
@@ -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");
index 78fcc39..0268055 100644 (file)
@@ -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);
 }