Add policy-admin table
authorSangwan Kwon <sangwan.kwon@samsung.com>
Tue, 29 Oct 2019 06:00:15 +0000 (15:00 +0900)
committerSangwan Kwon <sangwan.kwon@samsung.com>
Wed, 30 Oct 2019 04:46:01 +0000 (13:46 +0900)
Following queries are possible.
- SELECT * FROM policy_admin
- INSERT INTO policy_admin (name, uid) VALUES ('admin', 0)
- DELETE FROM policy_admin WHERE name = 'admin' AND uid = 0

Signed-off-by: Sangwan Kwon <sangwan.kwon@samsung.com>
12 files changed:
specs/tizen/policy_admin.table [new file with mode: 0644]
src/CMakeLists.txt
src/osquery/tables/tizen/policy_admin.cpp [new file with mode: 0644]
src/osquery/tables/tizen/tests/policy_tests.cpp
src/policyd/api.h
src/policyd/core/api.cpp
src/policyd/core/policy-manager.cpp
src/policyd/core/policy-manager.h
src/policyd/core/policy-storage.cpp
src/policyd/core/policy-storage.h
src/policyd/core/tests/storage-tests.cpp
src/vist/client/tests/client_tests.cpp

diff --git a/specs/tizen/policy_admin.table b/specs/tizen/policy_admin.table
new file mode 100644 (file)
index 0000000..03622f8
--- /dev/null
@@ -0,0 +1,9 @@
+table_name("policy_admin")
+description("Policy administrator.")
+schema([
+    Column("name", TEXT, "Policy admin name"),
+    Column("uid", INTEGER, "Policy admin uid"),
+])
+implementation("tizen/policy_admin@genPolicyAdmin")
+implementation_delete("tizen/policy_admin@deletePolicyAdmin")
+implementation_insert("tizen/policy_admin@insertPolicyAdmin")
index 20794edda7b24b552ba63d7700623ea403bfa2dc..d0646dfee0227d80b21dd5c7049567f4f1203587 100644 (file)
@@ -17,8 +17,8 @@ SET(TARGET_POLICYD_LIB policyd)
 SET(TARGET_VIST_LIB vist)
 
 ADD_SUBDIRECTORY(osquery)
-ADD_SUBDIRECTORY(vist)
 
 IF(DEFINED GBS_BUILD)
+       ADD_SUBDIRECTORY(vist)
        ADD_SUBDIRECTORY(policyd)
 ENDIF(DEFINED GBS_BUILD)
diff --git a/src/osquery/tables/tizen/policy_admin.cpp b/src/osquery/tables/tizen/policy_admin.cpp
new file mode 100644 (file)
index 0000000..035e86f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ *  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 <string>
+#include <memory>
+#include <stdexcept>
+
+#include <osquery/sql.h>
+#include <osquery/tables.h>
+
+#include <policyd/api.h>
+#include <vist/common/audit/logger.h>
+
+namespace {
+
+std::string getValue(std::string&& alias, const std::string& key)
+{
+       auto pos = alias.find(";");
+       auto token = alias.substr(0, pos);
+
+       if (token == key)
+               return alias.erase(0, pos + 1);
+       else
+               return std::string();
+}
+
+std::pair<std::string, int> parseAdmin(const std::string& request, bool insert = true)
+{
+       rapidjson::Document document;
+       document.Parse(request.c_str());
+       if (document.HasParseError() || !document.IsArray())
+               throw std::runtime_error("Cannot parse request.");
+
+       if (document.Size() != 2)
+               throw std::runtime_error("Wrong request format.");
+
+       if (insert) {
+               return std::make_pair(document[0].GetString(), document[1].GetInt());
+       } else { /// osquery transforms int to string in 'where clause' internally.
+               std::string name, uid;
+               std::string value = getValue(document[0].GetString(), "name");
+               if (!value.empty()) {
+                       name = value;
+                       uid = getValue(document[1].GetString(), "uid");
+               } else {
+                       name = getValue(document[1].GetString(), "name");
+                       uid = getValue(document[0].GetString(), "uid");
+               }
+
+               return std::make_pair(name, std::stoi(uid));
+       }
+}
+
+} // anonymous namespace
+
+namespace osquery {
+namespace tables {
+
+QueryData genPolicyAdmin(QueryContext& context) try {
+       INFO(VIST, "Select query about policy-admin.");
+
+       QueryData results;
+       auto admins = policyd::API::Admin::GetAll();
+
+       for (auto& admin : admins) {
+               Row r;
+               r["name"] = SQL_TEXT(admin.first);
+               r["uid"] = INTEGER(admin.second);
+
+               DEBUG(VIST, "Admin info [name]: " << r["name"] << ", [uid]: " << r["uid"]);
+               results.emplace_back(std::move(r));
+       }
+
+       return results;
+} catch (...) {
+       ERROR(VIST, "Failed to select query on policy-admin.");
+       Row r;
+       return { r };
+}
+
+QueryData insertPolicyAdmin(QueryContext& context, const PluginRequest& request) try {
+       INFO(VIST, "Insert query about policy-admin.");
+       if (request.count("json_value_array") == 0)
+               throw std::runtime_error("Wrong request format. Not found json value.");
+
+       auto admin = parseAdmin(request.at("json_value_array"));
+       DEBUG(VIST, "Admin info [name]: " << admin.first << ", [uid]: " << admin.second);
+       policyd::API::Admin::Enroll(admin.first, admin.second);
+
+       Row r;
+       r["status"] = "success";
+       return { r };
+} catch (...) {
+       ERROR(VIST, "Failed to insert query on policy-admin.");
+       Row r;
+       return { r };
+}
+
+QueryData deletePolicyAdmin(QueryContext& context, const PluginRequest& request) try {
+       INFO(VIST, "Delete query about policy-admin.");
+       if (request.count("json_value_array") == 0)
+               throw std::runtime_error("Wrong request format. Not found json value.");
+
+       auto admin = parseAdmin(request.at("json_value_array"), false);
+       DEBUG(VIST, "Admin info [name]: " << admin.first << ", [uid]: " << admin.second);
+       policyd::API::Admin::Disenroll(admin.first, admin.second);
+
+       Row r;
+       r["status"] = "success";
+       return { r };
+} catch (...) {
+       ERROR(VIST, "Failed to delete query on policy-admin.");
+       Row r;
+       return { r };
+}
+
+} // namespace tables
+} // namespace osquery
index c4a6f87d204285aaa6f046c29910981302b6dea4..4a3a9eb2ee5f3fa25eef91d9c27b9314cbe56c08 100644 (file)
@@ -25,3 +25,24 @@ TEST_F(PolicyTests, get_all) {
 
        EXPECT_TRUE(policies.size() > 0);
 }
+
+TEST_F(PolicyTests, get_admin_all) {
+       auto admins = policyd::API::Admin::GetAll();
+       EXPECT_EQ(admins.size(), 0);
+
+       policyd::API::Admin::Enroll("testAdmin", 0);
+       admins = policyd::API::Admin::GetAll();
+       EXPECT_EQ(admins.size(), 1);
+
+       policyd::API::Admin::Enroll("testAdmin", 1);
+       admins = policyd::API::Admin::GetAll();
+       EXPECT_EQ(admins.size(), 2);
+
+       policyd::API::Admin::Disenroll("testAdmin", 0);
+       admins = policyd::API::Admin::GetAll();
+       EXPECT_EQ(admins.size(), 1);
+
+       policyd::API::Admin::Disenroll("testAdmin", 1);
+       admins = policyd::API::Admin::GetAll();
+       EXPECT_EQ(admins.size(), 0);
+}
index 4632785c711a28c9b3ce53060e6b25dfcc2faa86..6fdb5bc9c40fed390dd2c4753db0dc690342f069 100644 (file)
@@ -19,6 +19,7 @@
 #include <policyd/sdk/policy-value.h>
 
 #include <string>
+#include <map>
 #include <unordered_map>
 
 namespace policyd {
@@ -32,6 +33,8 @@ struct API {
 
                static void Enroll(const std::string& admin, uid_t uid);
                static void Disenroll(const std::string& admin, uid_t uid);
+
+               static std::multimap<std::string, int> GetAll();
        };
 };
 
index 01757b5a0773c3b2ecc353129c1ead1b22e163ac..66d0bfd2880d436e3d5d6f7dccd404637cd87cf9 100644 (file)
@@ -46,4 +46,9 @@ void API::Admin::Disenroll(const std::string& admin, uid_t uid)
        PolicyManager::Instance().disenroll(admin, uid);
 }
 
+std::multimap<std::string, int> API::Admin::GetAll()
+{
+       return PolicyManager::Instance().getAdmins();
+}
+
 } // namespace policyd
index c08771e07f7b0140db5c2ff832520862818cefac..2d591451859c5c06c41feb45bd28da5478576530 100644 (file)
@@ -148,4 +148,9 @@ std::unordered_map<std::string, PolicyValue> PolicyManager::getAll(uid_t uid)
        return storage.strictest(uid);
 }
 
+std::multimap<std::string, int> PolicyManager::getAdmins()
+{
+       return storage.getAdmins();
+}
+
 } // namespace policyd
index 57eae0ee552ccd1deb032aa87992edd8afe7b420..9ab2b063e78febb0da9158c3c6f4db88f2fc3ac2 100644 (file)
@@ -22,6 +22,7 @@
 #include "policy-storage.h"
 
 #include <exception>
+#include <map>
 #include <memory>
 #include <string>
 #include <unordered_map>
@@ -50,9 +51,10 @@ public:
        void set(const std::string& policy, const PolicyValue& value,
                         const std::string& admin, uid_t uid = 0);
        PolicyValue get(const std::string& policy, uid_t uid = 0);
-
        std::unordered_map<std::string, PolicyValue> getAll(uid_t uid = 0);
 
+       std::multimap<std::string, int> getAdmins();
+
 private:
        explicit PolicyManager();
        ~PolicyManager() = default;
index 31cdc7f8dc1c77f050daa822ae3a52eaafdff89b..afd2463fb494635c586cce8d3760f56c9f221e64 100644 (file)
@@ -297,6 +297,22 @@ std::unordered_map<std::string, PolicyValue> PolicyStorage::strictest(uid_t uid)
        return policies;
 }
 
+std::multimap<std::string, int> PolicyStorage::getAdmins()
+{
+       std::multimap<std::string, int> admins;
+       for (const auto& pair : this->admins) {
+               std::string alias = pair.first;
+               int uid = pair.second.uid;
+               /// Erase uid from alias(name + uid)
+               std::size_t pos = alias.rfind(std::to_string(uid));
+               alias.erase(pos, std::to_string(uid).size());
+
+               admins.emplace(std::move(alias), uid);
+       }
+
+       return admins;
+}
+
 std::string PolicyStorage::getAlias(const std::string& name, uid_t uid) const noexcept
 {
        return name + std::to_string(uid);
index 439106e8803e18a753b74a870feeeb671b93c3c0..d2e39e7d52bec7aed1616b2123a9a58e15ded88b 100644 (file)
 
 #include "db-schema.h"
 
+#include <map>
 #include <memory>
-#include <vector>
 #include <unordered_map>
+#include <vector>
 
 #include <klay/db/connection.h>
 
@@ -60,6 +61,9 @@ public:
        /// Return all strictest policy values
        std::unordered_map<std::string, PolicyValue> strictest(uid_t uid = 0);
 
+       /// Admin name can be duplicated
+       std::multimap<std::string, int> getAdmins();
+
 private:
        std::string getScript(const std::string& name);
        std::string getAlias(const std::string& name, uid_t uid) const noexcept;
index b0f7ab857a72e2cdfd531a98699008f3c7e61e42..d533c67605836eef91319f9fbcd5a1c8906392a5 100644 (file)
@@ -137,3 +137,26 @@ TEST_F(PolicyStorageTests, strictest_all) {
 
        storage->disenroll("testAdmin", 1);
 }
+
+TEST_F(PolicyStorageTests, admin_list) {
+       auto storage = getStorage();
+
+       auto admins = storage->getAdmins();
+       EXPECT_EQ(admins.size(), 0);
+
+       storage->enroll("testAdmin", 1);
+       admins = storage->getAdmins();
+       EXPECT_EQ(admins.size(), 1);
+
+       storage->enroll("testAdmin", 2);
+       admins = storage->getAdmins();
+       EXPECT_EQ(admins.size(), 2);
+
+       storage->disenroll("testAdmin", 2);
+       admins = storage->getAdmins();
+       EXPECT_EQ(admins.size(), 1);
+
+       storage->disenroll("testAdmin", 1);
+       admins = storage->getAdmins();
+       EXPECT_EQ(admins.size(), 0);
+}
index d05d5dba7a7a9a22a4f868aadcd2b15cc5a194e5..d48b003d12b5fc95ae51b56f205b94b5f6974ac9 100644 (file)
@@ -30,3 +30,26 @@ TEST_F(ClientTests, query) {
 
        EXPECT_TRUE(rows.size() > 0);
 }
+
+TEST_F(ClientTests, admin_enrollment) {
+       auto rows = Query::Execute("INSERT INTO policy_admin (name, uid) "
+                                                          "VALUES ('testAdmin', 0)");
+       EXPECT_EQ(rows.size(), 0);
+
+       rows = Query::Execute("SELECT * FROM policy_admin");
+       EXPECT_EQ(rows.size(), 1);
+
+       Query::Execute("INSERT INTO policy_admin (name, uid) VALUES ('testAdmin', 1)");
+       rows = Query::Execute("SELECT * FROM policy_admin");
+       EXPECT_EQ(rows.size(), 2);
+
+       rows = Query::Execute("DELETE FROM policy_admin WHERE uid = 0 AND name = 'testAdmin'");
+       EXPECT_EQ(rows.size(), 0);
+
+       rows = Query::Execute("SELECT * FROM policy_admin");
+       EXPECT_EQ(rows.size(), 1);
+
+       Query::Execute("DELETE FROM policy_admin WHERE name = 'testAdmin' AND uid = 1");
+       rows = Query::Execute("SELECT * FROM policy_admin");
+       EXPECT_EQ(rows.size(), 0);
+}