--- /dev/null
+/*
+ * 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
+ */
+
+CREATE TABLE IF NOT EXISTS admin (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ pkg TEXT NOT NULL,
+ uid INTEGER,
+ key TEXT,
+ removable INTEGER
+);
+
+CREATE TABLE IF NOT EXISTS managed_policy (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ aid INTEGER,
+ pid INTEGER,
+ value INTEGER
+);
+
+CREATE TABLE IF NOT EXISTS policy_definition (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ scope INTEGER,
+ name TEXT NOT NULL,
+ ivalue INTEGER
+);
+
+CREATE TRIGGER IF NOT EXISTS prepare_storage AFTER INSERT ON admin
+FOR EACH ROW
+BEGIN
+ INSERT INTO managed_policy(aid, pid, value)
+ SELECT NEW.ID, policy_definition.id, policy_definition.ivalue
+ FROM policy_definition;
+END;
+
+CREATE TRIGGER IF NOT EXISTS remove_storage AFTER DELETE ON admin
+FOR EACH ROW
+BEGIN
+ DELETE FROM managed_policy WHERE managed_policy.aid = OLD.ID;
+END;
Requires: procps-ng
Requires: libsystemd
-%global user_name security_fw
-%global group_name security_fw
-%global smack_label System
+%global user_name security_fw
+%global group_name security_fw
+%global smack_label System
-%global dpm_base %{TZ_SYS_DATA}/dpm
-%global dpm_event %{dpm_base}/event
-%global dpm_plugins %{_libdir}/dpm/plugins
+%global ro_dir %{_datadir}
+%global rw_dir %{TZ_SYS_DATA}
+
+%global vist_ro_dir %{ro_dir}/vist
+%global vist_rw_dir %{rw_dir}/vist
+
+%global vist_db_dir %{vist_rw_dir}/db
+%global vist_plugin_dir %{vist_ro_dir}/plugin
+%global vist_script_dir %{vist_ro_dir}/script
%description
Osquery exposes an operating system as a high-performance relational database.
-DUSER_NAME=%{user_name} \
-DGROUP_NAME=%{group_name} \
-DSMACK_LABEL=%{smack_label} \
- -DSCRIPT_INSTALL_DIR=%{_scriptdir} \
- -DSYSTEMD_UNIT_INSTALL_DIR=%{_unitdir} \
- -DDATA_INSTALL_DIR=%{dpm_base} \
- -DEVENT_CONFIGURE_DIR=%{dpm_event} \
- -DPLUGIN_INSTALL_DIR=%{dpm_plugins} \
- -DDB_INSTALL_DIR=%{TZ_SYS_DB} \
- -DRUN_INSTALL_DIR=%{TZ_SYS_RUN} \
- -DAPP_INSTALL_PREFIX="%{TZ_SYS_RO_APP}" \
- -DAPP_SHARE_PACKAGES_DIR="%{TZ_SYS_RO_PACKAGES}" \
- -DPAMD_INSTALL_DIR=/etc/pam.d \
- -DDBUS_CONFIGURE_DIR=/etc/dbus-1/system.d \
- -DDBUS_SERVICE_DIR=/usr/share/dbus-1/system-services
+ -DDB_INSTALL_DIR:PATH=%{vist_db_dir} \
+ -DPLUGIN_INSTALL_DIR:PATH=%{vist_plugin_dir} \
+ -DSCRIPT_INSTALL_DIR:PATH=%{vist_script_dir}
make %{?jobs:-j%jobs}
%install
%make_install
-mkdir -p %{buildroot}%{dpm_event}
-mkdir -p %{buildroot}%{dpm_plugins}
-mkdir -p %{buildroot}/%{_unitdir}/multi-user.target.wants
-mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants
+mkdir -p %{buildroot}/%{vist_db_dir}
+mkdir -p %{buildroot}/%{vist_plugin_dir}
+mkdir -p %{buildroot}/%{vist_script_dir}
+
+cp data/script/*.sql %{buildroot}/%{vist_script_dir}
%clean
rm -rf %{buildroot}
+%files
+%manifest %{name}.manifest
+%{vist_script_dir}/*.sql
+%dir %attr(-, %{user_name}, %{group_name}) %{vist_db_dir}
+
## Test Package ##############################################################
%package test
Summary: Osquery test
Testcases for osquery
%files test
-%manifest %{name}.manifest
%{_bindir}/osquery-test
%{_bindir}/apix-test
%{_bindir}/policyd-test
-## DPM Plugins - ############################################################
+## ViST Plugins - ###########################################################
%package policyd-plugins
-Summary: DPM plugins
+Summary: ViST plugins
Group: Security/Other
## Common
BuildRequires: pkgconfig(buxton2)
%files policyd-plugins
%manifest packaging/%{name}-plugins.manifest
-%{_libdir}/dpm/plugins/bluetooth
+%{vist_plugin_dir}/bluetooth
INCLUDE_DIRECTORIES(SYSTEM . ${POLICYD_DEPS_INCLUDE_DIRS})
-ADD_DEFINITIONS(-DDATA_PATH="${DATA_INSTALL_DIR}"
- -DRUN_PATH="${RUN_INSTALL_DIR}"
- -DDB_PATH="${DB_INSTALL_DIR}/.dpm.db"
+ADD_DEFINITIONS(-DDB_PATH="${DB_INSTALL_DIR}/.vist.db"
-DPLUGIN_INSTALL_DIR="${PLUGIN_INSTALL_DIR}"
- -DEVENT_CONFIGURE_DIR="${EVENT_CONFIGURE_DIR}")
-ADD_DEFINITIONS(-DUG_WAYLAND)
+ -DSCRIPT_INSTALL_DIR="${SCRIPT_INSTALL_DIR}")
ADD_SUBDIRECTORY(core)
ADD_SUBDIRECTORY(sdk)
#include <memory>
#include <mutex>
-#define DPM Logger::GetLogSink("DPM")
+#define VIST Logger::GetLogSink("VIST")
namespace policyd {
{
loadProviders(PLUGIN_INSTALL_DIR);
int cnt = loadPolicies();
- INFO(DPM, std::to_string(cnt) + "-policies loaded");
+ INFO(VIST, std::to_string(cnt) + "-policies loaded");
}
std::pair<int, int> PolicyManager::loadProviders(const std::string& path)
{
- INFO(DPM, "Load policies from :" << path);
+ INFO(VIST, "Load policies from :" << path);
klay::File dir(path);
if (!dir.exists() || !dir.isDirectory())
throw std::invalid_argument("Plugin directory is wrong.: " + path);
try {
auto provider = PolicyLoader::load(iter->getPath());
- DEBUG(DPM, "Loaded provider: " << provider->getName());
+ DEBUG(VIST, "Loaded provider: " << provider->getName());
this->providers.emplace_back(std::move(provider));
} catch (const std::exception& e) {
++failed;
- ERROR(DPM, "Failed to load: " << iter->getPath() << e.what());
+ ERROR(VIST, "Failed to load: " << iter->getPath() << e.what());
continue;
}
++passed;
}
- INFO(DPM, "Loaded result >> passed: " << passed << ", failed: " << failed);
+ INFO(VIST, "Loaded result >> passed: " << passed << ", failed: " << failed);
return std::make_pair(passed, failed);
}
this->domain.insert(p->domain.cbegin(), p->domain.cend());
}
+ bool changed = false;
for (const auto& g : global) {
- if (!storage.exists(g.first))
- throw std::runtime_error("Policy does not exist.: " + g.first);
+ if (!storage.exists(g.first)) {
+ INFO(VIST, "Define global policy: " << g.first);
+ storage.define(0, g.first, g.second->getInitial().value);
+ changed = true;
+ }
}
for (const auto& d : domain) {
- if (!storage.exists(d.first))
- throw std::runtime_error("Policy does not exist.: " + d.first);
+ if (!storage.exists(d.first)) {
+ INFO(VIST, "Define domain policy: " << d.first);
+ storage.define(1, d.first, d.second->getInitial().value);
+ changed = true;
+ }
}
+ if (changed)
+ storage.syncPolicyDefinition();
+
return global.size() + domain.size();
}
#include <klay/db/statement.h>
#include <klay/exception.h>
+#include <fstream>
+
using namespace query_builder;
using namespace policyd::schema;
make_column("scope", &PolicyDefinition::scope),
make_column("name", &PolicyDefinition::name),
make_column("ivalue", &PolicyDefinition::ivalue));
+
+const std::string SCRIPT_BASE = SCRIPT_INSTALL_DIR;
+const std::string SCRIPT_CREATE_SCHEMA = "create_schema";
+
} // anonymous namespace
namespace policyd {
database::Connection::ReadWrite |
database::Connection::Create))
{
+ database->exec("PRAGMA foreign_keys = ON;");
+ database->exec(getScript(SCRIPT_CREATE_SCHEMA));
+
sync();
}
void PolicyStorage::sync()
{
- DEBUG(DPM, "Sync policy storage to cache object.");
+ DEBUG(VIST, "Sync policy storage to cache object.");
syncPolicyDefinition();
syncAdmin();
syncManagedPolicy();
pd.scope = stmt.getColumn(1);
pd.name = std::string(stmt.getColumn(2));
pd.ivalue = stmt.getColumn(3);
- DEBUG(DPM, "Defined policy:" + pd.name);
+ DEBUG(VIST, "Defined policy:" + pd.name);
this->definitions.emplace(pd.name, std::move(pd));
}
}
}
}
+std::string PolicyStorage::getScript(const std::string& name)
+{
+ std::string path = SCRIPT_BASE + "/" + name + ".sql";
+ std::ifstream is(path);
+ if (is.fail())
+ throw std::invalid_argument("Failed to open script: " + path);
+
+ std::istreambuf_iterator<char> begin(is), end;
+ auto content = std::string(begin, end);
+ if (content.empty())
+ throw std::runtime_error("Failed to read script: " + path);
+
+ return content;
+}
+
+void PolicyStorage::define(int scope, const std::string& policy, int ivalue)
+{
+ if (definitions.find(policy) != definitions.end()) {
+ INFO(VIST, "Policy is already defined: " + policy);
+ return;
+ }
+
+ PolicyDefinition pd;
+ pd.scope = scope;
+ pd.name = policy;
+ pd.ivalue = ivalue;
+
+ std::string insertQuery = definitionTable.insert(&PolicyDefinition::scope,
+ &PolicyDefinition::name,
+ &PolicyDefinition::ivalue);
+ database::Statement stmt(*database, insertQuery);
+ stmt.bind(1, pd.scope);
+ stmt.bind(2, pd.name);
+ stmt.bind(3, pd.ivalue);
+ if (!stmt.exec())
+ throw std::runtime_error("Failed to define policy: " + pd.name);
+}
+
void PolicyStorage::enroll(const std::string& name, uid_t uid)
{
std::string alias = getAlias(name, uid);
- INFO(DPM, "Enroll admin: " + alias);
+ INFO(VIST, "Enroll admin: " + alias);
if (admins.find(alias) != admins.end()) {
- ERROR(DPM, "Admin is aleady enrolled.: " + alias);
+ ERROR(VIST, "Admin is aleady enrolled.: " + alias);
return;
}
stmt.bind(3, admin.key);
stmt.bind(4, admin.removable);
if (!stmt.exec())
- throw std::runtime_error("Failed to enroll admin.: " + admin.pkg);
+ throw std::runtime_error("Failed to enroll admin: " + admin.pkg);
/// Sync admin for getting admin ID.
syncAdmin();
syncManagedPolicy();
int count = managedPolicies.size() / admins.size();
- INFO(DPM, "Admin[" + alias + "] manages " + std::to_string(count) + "-policies.");
+ INFO(VIST, "Admin[" + alias + "] manages " + std::to_string(count) + "-policies.");
}
void PolicyStorage::disenroll(const std::string& name, uid_t uid)
{
std::string alias = getAlias(name, uid);
- INFO(DPM, "Disenroll admin: " + alias);
+ INFO(VIST, "Disenroll admin: " + alias);
if (admins.find(alias) == admins.end()) {
- ERROR(DPM, "Not exist admin: " + alias);
+ ERROR(VIST, "Not exist admin: " + alias);
return;
} else {
admins.erase(alias);
if (definitions.find(policy) == definitions.end())
throw std::runtime_error("Not exist policy: " + policy);
- DEBUG(DPM, "Policy-update is called by admin: " + alias + ", about: " + policy +
+ DEBUG(VIST, "Policy-update is called by admin: " + alias + ", about: " + policy +
", value: " + std::to_string(value));
int policyId = definitions[policy].id;
else
strictest->value = (*strictest < value) ? strictest->value : value;
- DEBUG(DPM, "The strictest of policy[" + policy +
- "] : " + std::to_string(strictest->value));
+ DEBUG(VIST, "The strictest of policy[" + policy +
+ "] : " + std::to_string(strictest->value));
}
if (strictest == nullptr)
/// TODO(Sangwan): Consider to support lazy sync
void sync();
+ void syncPolicyDefinition();
+ void syncAdmin();
+ void syncManagedPolicy();
+
inline bool exists(const std::string& policy) const noexcept {
return definitions.find(policy) != definitions.end();
}
void enroll(const std::string& admin, uid_t uid);
void disenroll(const std::string& admin, uid_t uid);
+ void define(int scope, const std::string& policy, int ivalue);
void update(const std::string& admin, uid_t uid,
const std::string& policy, const PolicyValue& value);
std::unordered_map<std::string, PolicyValue> strictest(uid_t uid = 0);
private:
- void syncPolicyDefinition();
- void syncAdmin();
- void syncManagedPolicy();
-
+ std::string getScript(const std::string& name);
std::string getAlias(const std::string& name, uid_t uid) const noexcept;
int getUid(int adminId) const noexcept;
bool isRaised = false;
try {
+ // DB is maden at run-time
PolicyStorage storage("/tmp/dummy");
} catch (const std::exception&) {
isRaised = true;
}
- EXPECT_TRUE(isRaised);
+ EXPECT_FALSE(isRaised);
}
TEST_F(PolicyStorageTests, enrollment) {