From 315409375e5ae973a520560b62cbe9a5c98dde83 Mon Sep 17 00:00:00 2001 From: "i.metelytsia" Date: Tue, 10 Apr 2018 18:06:02 +0300 Subject: [PATCH] AuditRuleManager updated --- device-agent/daemon/audit/rule.cpp | 154 +++++----- device-agent/daemon/audit/rule.h | 438 +++++++++++++++-------------- device-agent/daemon/audit/rule_manager.cpp | 69 ++++- device-agent/daemon/audit/rule_manager.h | 7 + device-agent/utest/test_rule.cpp | 14 +- 5 files changed, 378 insertions(+), 304 deletions(-) diff --git a/device-agent/daemon/audit/rule.cpp b/device-agent/daemon/audit/rule.cpp index 3ba3ae1..06f8d0d 100644 --- a/device-agent/daemon/audit/rule.cpp +++ b/device-agent/daemon/audit/rule.cpp @@ -23,53 +23,53 @@ namespace audit { -const std::map Rule::Field::s_fields = { - {AUDIT_PID, {"pid",Rule::FieldType::t_int}}, - {AUDIT_UID, {"uid",Rule::FieldType::t_int}}, - {AUDIT_EUID, {"euid",Rule::FieldType::t_int}}, - {AUDIT_SUID, {"suid",Rule::FieldType::t_int}}, - {AUDIT_FSUID, {"fsuid",Rule::FieldType::t_int}}, - {AUDIT_GID, {"gid",Rule::FieldType::t_int}}, - {AUDIT_EGID, {"egid",Rule::FieldType::t_int}}, - {AUDIT_SGID, {"sgid",Rule::FieldType::t_int}}, - {AUDIT_FSGID, {"fsgid",Rule::FieldType::t_int}}, - {AUDIT_LOGINUID, {"loginuid",Rule::FieldType::t_int}}, +const std::map Field::s_fields = { + {AUDIT_PID, {"pid",FieldType::t_int}}, + {AUDIT_UID, {"uid",FieldType::t_int}}, + {AUDIT_EUID, {"euid",FieldType::t_int}}, + {AUDIT_SUID, {"suid",FieldType::t_int}}, + {AUDIT_FSUID, {"fsuid",FieldType::t_int}}, + {AUDIT_GID, {"gid",FieldType::t_int}}, + {AUDIT_EGID, {"egid",FieldType::t_int}}, + {AUDIT_SGID, {"sgid",FieldType::t_int}}, + {AUDIT_FSGID, {"fsgid",FieldType::t_int}}, + {AUDIT_LOGINUID, {"loginuid",FieldType::t_int}}, // {AUDIT_PERS, {"pers",???}}, - {AUDIT_ARCH, {"arch",Rule::FieldType::t_str}}, + {AUDIT_ARCH, {"arch",FieldType::t_str}}, // {AUDIT_MSGTYPE, {"msgtype",???}}, // {AUDIT_SUBJ_USER, {"subj_user",???}}, // {AUDIT_SUBJ_ROLE, {"subj_role",???}}, - {AUDIT_SUBJ_TYPE, {"subj_type",Rule::FieldType::t_int}}, + {AUDIT_SUBJ_TYPE, {"subj_type",FieldType::t_int}}, // {AUDIT_SUBJ_SEN, {"subj_sen",???}}, // {AUDIT_SUBJ_CLR, {"subj_clr",???}}, - {AUDIT_PPID, {"ppid",Rule::FieldType::t_int}}, + {AUDIT_PPID, {"ppid",FieldType::t_int}}, // {AUDIT_OBJ_USER, {"obj_user",???}}, // {AUDIT_OBJ_ROLE, {"obj_role",???}}, - {AUDIT_OBJ_TYPE, {"obj_type",Rule::FieldType::t_int}}, + {AUDIT_OBJ_TYPE, {"obj_type",FieldType::t_int}}, // {AUDIT_OBJ_LEV_LOW, {"obj_lev_low",???}}, // {AUDIT_OBJ_LEV_HIGH, {"obj_lev_high",???}}, - {AUDIT_LOGINUID_SET, {"loginuid_set",Rule::FieldType::t_int}}, - {AUDIT_DEVMAJOR, {"dev_major",Rule::FieldType::t_int}}, - {AUDIT_DEVMINOR, {"dev_minor",Rule::FieldType::t_int}}, - {AUDIT_INODE, {"inode",Rule::FieldType::t_int}}, - {AUDIT_EXIT, {"exit",Rule::FieldType::t_int}}, - {AUDIT_SUCCESS, {"success",Rule::FieldType::t_int}}, - {AUDIT_WATCH, {"watch",Rule::FieldType::t_str}}, - {AUDIT_PERM, {"perm",Rule::FieldType::t_int}}, + {AUDIT_LOGINUID_SET, {"loginuid_set",FieldType::t_int}}, + {AUDIT_DEVMAJOR, {"dev_major",FieldType::t_int}}, + {AUDIT_DEVMINOR, {"dev_minor",FieldType::t_int}}, + {AUDIT_INODE, {"inode",FieldType::t_int}}, + {AUDIT_EXIT, {"exit",FieldType::t_int}}, + {AUDIT_SUCCESS, {"success",FieldType::t_int}}, + {AUDIT_WATCH, {"watch",FieldType::t_str}}, + {AUDIT_PERM, {"perm",FieldType::t_int}}, // {AUDIT_DIR, {"dir",???}}, // {AUDIT_FILETYPE, {"filetype",???}}, - {AUDIT_OBJ_UID, {"obj_uid",Rule::FieldType::t_int}}, - {AUDIT_OBJ_GID, {"obj_gid",Rule::FieldType::t_int}}, + {AUDIT_OBJ_UID, {"obj_uid",FieldType::t_int}}, + {AUDIT_OBJ_GID, {"obj_gid",FieldType::t_int}}, // {AUDIT_FIELD_COMPARE, {"compare",???}}, // {AUDIT_EXE, {"exe",???}}, - {AUDIT_ARG0, {"arg0",Rule::FieldType::t_int}}, - {AUDIT_ARG1, {"arg1",Rule::FieldType::t_int}}, - {AUDIT_ARG2, {"arg2",Rule::FieldType::t_int}}, - {AUDIT_ARG3, {"arg3",Rule::FieldType::t_int}}, - {AUDIT_FILTERKEY, {"filter_key",Rule::FieldType::t_str}}, + {AUDIT_ARG0, {"arg0",FieldType::t_int}}, + {AUDIT_ARG1, {"arg1",FieldType::t_int}}, + {AUDIT_ARG2, {"arg2",FieldType::t_int}}, + {AUDIT_ARG3, {"arg3",FieldType::t_int}}, + {AUDIT_FILTERKEY, {"filter_key",FieldType::t_str}}, }; -const std::map Rule::Operation::s_operations = { +const std::map Operation::s_operations = { {AUDIT_BIT_MASK, "bit_mask"}, {AUDIT_LESS_THAN, "less"}, {AUDIT_GREATER_THAN, "greater"}, @@ -84,35 +84,37 @@ void syscallCallback(unsigned int syscall, void* user_data) { assert(user_data); Rule* rule = reinterpret_cast(user_data); - rule->m_syscall.insert(syscall); + rule->m_data.m_syscall.insert(syscall); } void conditionCallback(unsigned int field, unsigned int operation, const void* value, void* user_data) { assert(user_data); Rule* rule = reinterpret_cast(user_data); - Rule::Field f(field); + Field f(field); if ((int)f == AUDIT_FILTERKEY) { - rule->m_key = (const char*)value; + rule->m_data.m_key = (const char*)value; } else { - if (f.valueType() == Rule::FieldType::t_int) { - rule->m_condition.push_back({(int)field,(int)operation,(int)value}); - } else if (f.valueType() == Rule::FieldType::t_str) { - rule->m_condition.push_back({(int)field,(int)operation,(const char*)value}); + if (f.type() == FieldType::t_int) { + rule->m_data.m_condition.push_back({(int)field,(int)operation,(int)value}); + } else if (f.type() == FieldType::t_str) { + rule->m_data.m_condition.push_back({(int)field,(int)operation,(const char*)value}); } } } -Rule::Rule(const std::string& key) : m_destroy_handle(true), m_handle(nullptr), m_key(key), m_syscall{}, m_condition{} +Rule::Rule(const std::string& key) : m_handle(nullptr), m_data() { + m_data.m_key = key; + if (audit_rule_create(&m_handle) != AUDIT_TRAIL_ERROR_NONE) { throw std::runtime_error("Failed to create audit rule!"); } - if (audit_rule_add_condition(m_handle, AUDIT_FILTERKEY, AUDIT_EQUAL, (void*)m_key.c_str()) != AUDIT_TRAIL_ERROR_NONE) { + if (audit_rule_add_condition(m_handle, AUDIT_FILTERKEY, AUDIT_EQUAL, (void*)m_data.m_key.c_str()) != AUDIT_TRAIL_ERROR_NONE) { throw std::runtime_error("Failed to set audit rule key!"); } } -Rule::Rule(audit_rule_h handle) : m_destroy_handle(false), m_handle(handle), m_key(), m_syscall{}, m_condition{} +Rule::Rule(audit_rule_h handle) : m_handle(handle), m_data() { if (audit_rule_foreach_systemcall(m_handle, syscallCallback, this) != AUDIT_TRAIL_ERROR_NONE) { throw std::runtime_error("audit_rule_foreach_systemcall failed!"); @@ -121,69 +123,41 @@ Rule::Rule(audit_rule_h handle) : m_destroy_handle(false), m_handle(handle), m_k throw std::runtime_error("audit_rule_foreach_condition failed!"); } } -Rule::Rule(const Json::Value& rule) : m_destroy_handle(true), m_handle(nullptr), m_key(), m_syscall{}, m_condition{} +Rule::Rule(const RuleData& data) : m_handle(nullptr), m_data(data) { if(audit_rule_create(&m_handle) != AUDIT_TRAIL_ERROR_NONE) { throw std::runtime_error("Failed to create audit rule!"); } - if (rule.empty()) { - throw std::logic_error("Empty rule!"); - } - - m_key = rule.get("key", "").asString(); - if (m_key == "") { - throw std::logic_error("Field \"key\" is undefined!"); - } - if (audit_rule_add_condition(m_handle, AUDIT_FILTERKEY, AUDIT_EQUAL, (void*)m_key.c_str()) != AUDIT_TRAIL_ERROR_NONE) { + if (audit_rule_add_condition(m_handle, AUDIT_FILTERKEY, AUDIT_EQUAL, (void*)m_data.m_key.c_str()) != AUDIT_TRAIL_ERROR_NONE) { throw std::runtime_error("Failed to set audit rule key!"); } - const Json::Value& syscall = rule["syscall"]; - if (!syscall.empty()) { - for (const Json::Value& v : syscall) { - if (addSyscall(v.asInt()) != 0) { - throw std::runtime_error("Can't add syscall!"); - } + for (int v : m_data.m_syscall) { + if (audit_rule_add_systemcall(m_handle, v) != AUDIT_TRAIL_ERROR_NONE) { + throw std::runtime_error("Can't add syscall!"); } } - const Json::Value& condition = rule["condition"]; - if (!condition.empty()) { - for (const Json::Value& node : condition) { - if (!node.isMember("field") || !node.isMember("operator") || !node.isMember("value")) { - throw std::logic_error("Invalid condition format!"); - } - std::string f = node.get("field", "").asString(); - std::string o = node.get("operator", "").asString(); - Json::Value v = node.get("value", Json::Value::null); - if (v.isInt()) { - if (addCondition(f, o, v.asInt()) != 0) { - throw std::runtime_error("Can't add condition!"); - } - } else { - if (addCondition(f, o, v.asString()) != 0) { - throw std::runtime_error("Can't add condition!"); - } - } + for (const Condition& c : m_data.m_condition) { + if (audit_rule_add_condition(m_handle, c.m_field, c.m_operation, (void*)c.m_value) != AUDIT_TRAIL_ERROR_NONE) { + throw std::runtime_error("Can't add condition!"); } } } Rule::~Rule() { - if (m_destroy_handle) { - audit_rule_destroy(m_handle); - } + audit_rule_destroy(m_handle); } int Rule::addSyscall(int syscall) { int res = 0; - if (m_syscall.find(syscall) == m_syscall.end()) { + if (m_data.m_syscall.find(syscall) == m_data.m_syscall.end()) { if ((res = audit_rule_add_systemcall(m_handle, syscall)) == AUDIT_TRAIL_ERROR_NONE) { - m_syscall.insert(syscall); + m_data.m_syscall.insert(syscall); } } @@ -194,9 +168,9 @@ int Rule::removeSyscall(int syscall) { int res = 0; - if (m_syscall.find(syscall) != m_syscall.end()) { + if (m_data.m_syscall.find(syscall) != m_data.m_syscall.end()) { if ((res = audit_rule_remove_systemcall(m_handle, syscall)) == AUDIT_TRAIL_ERROR_NONE) { - m_syscall.erase(syscall); + m_data.m_syscall.erase(syscall); } } @@ -209,7 +183,7 @@ int Rule::addCondition(const std::string& field, const std::string& operation, i Condition c{field, operation, value}; if ((res = audit_rule_add_condition(m_handle, c.m_field, c.m_operation, (void*)value)) == AUDIT_TRAIL_ERROR_NONE) { - m_condition.push_back(c); + m_data.m_condition.push_back(c); } return res; @@ -220,7 +194,7 @@ int Rule::addCondition(const std::string& field, const std::string& operation, c Condition c{field, operation, value}; if ((res = audit_rule_add_condition(m_handle, c.m_field, c.m_operation, (void*)value.c_str())) == AUDIT_TRAIL_ERROR_NONE) { - m_condition.push_back(c); + m_data.m_condition.push_back(c); } return res; @@ -231,10 +205,10 @@ int Rule::removeCondition(const std::string& field, const std::string& operation int res = 0; Condition c{field, operation, value}; - ConditionList::iterator it = std::find(m_condition.begin(), m_condition.end(), c); - if (it != m_condition.end()) { + ConditionList::iterator it = std::find(m_data.m_condition.begin(), m_data.m_condition.end(), c); + if (it != m_data.m_condition.end()) { if ((res = audit_rule_remove_condition(m_handle, c.m_field, c.m_operation, (void*)value)) == AUDIT_TRAIL_ERROR_NONE) { - m_condition.erase(it); + m_data.m_condition.erase(it); } } @@ -245,10 +219,10 @@ int Rule::removeCondition(const std::string& field, const std::string& operation int res = 0; Condition c{field, operation, value}; - ConditionList::iterator it = std::find(m_condition.begin(), m_condition.end(), c); - if (it != m_condition.end()) { + ConditionList::iterator it = std::find(m_data.m_condition.begin(), m_data.m_condition.end(), c); + if (it != m_data.m_condition.end()) { if ((res = audit_rule_remove_condition(m_handle, c.m_field, c.m_operation, (void*)value.c_str())) == AUDIT_TRAIL_ERROR_NONE) { - m_condition.erase(it); + m_data.m_condition.erase(it); } } diff --git a/device-agent/daemon/audit/rule.h b/device-agent/daemon/audit/rule.h index 5133594..c16f07c 100644 --- a/device-agent/daemon/audit/rule.h +++ b/device-agent/daemon/audit/rule.h @@ -32,216 +32,278 @@ namespace audit { /** - * @class Rule - * @brief Audit rule representation + * @class SyscallArray + * @brief Array of syscall indexes */ -class Rule +class SyscallArray : public std::set { - /** - * @class SyscallArray - * @brief Array of syscall indexes - */ - class SyscallArray : public std::set - { - public: - Json::Value asJson() const { - Json::Value res(Json::arrayValue); - for (auto i : *this) { - res.append(i); - } - return res; +public: + Json::Value asJson() const { + Json::Value res(Json::arrayValue); + for (auto i : *this) { + res.append(i); } - }; + return res; + } +}; - /** - * @enum FieldType - * @brief Supported audit rule field types - */ - enum class FieldType - { - t_int, - t_str, - }; +/** + * @enum FieldType + * @brief Supported audit rule field types + */ +enum class FieldType +{ + t_int, + t_str, +}; - /** - * @class Field - * @brief Audit rule condition field - */ - class Field +/** + * @class Field + * @brief Audit rule condition field + */ +class Field +{ + struct FieldData { - struct FieldData - { - std::string name; - FieldType type; - }; + std::string name; + FieldType type; + }; - static const std::map s_fields; + static const std::map s_fields; - public: - Field(int field) : m_field(field) { - if (s_fields.find(m_field) == s_fields.end()) { - throw std::logic_error("Unsupported audit rule condition field!"); - } +public: + Field(int field) : m_field(field) { + if (s_fields.find(m_field) == s_fields.end()) { + throw std::logic_error("Unsupported audit rule condition field!"); } - Field(const std::string& field) : m_field(-1) { - for (const auto& i : s_fields) { - if (i.second.name == field) { - m_field = i.first; - break; - } - } - if (m_field == -1) { - throw std::logic_error("Unsupported audit rule condition field!"); + } + Field(const std::string& field) : m_field(-1) { + for (const auto& i : s_fields) { + if (i.second.name == field) { + m_field = i.first; + break; } } - - FieldType valueType() const { - return s_fields.find(m_field)->second.type; + if (m_field == -1) { + throw std::logic_error("Unsupported audit rule condition field!"); } + } - operator int() const { - return m_field; - } + FieldType type() const { + return s_fields.find(m_field)->second.type; + } - operator std::string() const { - return s_fields.find(m_field)->second.name; - } + operator int() const { + return m_field; + } - friend bool operator ==(const Field& lv, const Field& rv) { - return lv.m_field == rv.m_field; - } + operator std::string() const { + return s_fields.find(m_field)->second.name; + } - private: - int m_field; - }; + friend bool operator ==(const Field& lv, const Field& rv) { + return lv.m_field == rv.m_field; + } - /** - * @class Operation - * @brief Audit rule condition operation - */ - class Operation - { - static const std::map s_operations; +private: + int m_field; +}; - public: - Operation(int operation) : m_operation(operation) { - if (s_operations.find(m_operation) == s_operations.end()) { - throw std::logic_error("Unsupported audit rule condition operation!"); - } +/** + * @class Operation + * @brief Audit rule condition operation + */ +class Operation +{ + static const std::map s_operations; + +public: + Operation(int operation) : m_operation(operation) { + if (s_operations.find(m_operation) == s_operations.end()) { + throw std::logic_error("Unsupported audit rule condition operation!"); } - Operation(const std::string& operation) : m_operation(-1) { - for (const auto& i : s_operations) { - if (i.second == operation) { - m_operation = i.first; - break; - } - } - if (m_operation == -1) { - throw std::logic_error("Unsupported audit rule condition operation!"); + } + Operation(const std::string& operation) : m_operation(-1) { + for (const auto& i : s_operations) { + if (i.second == operation) { + m_operation = i.first; + break; } } - - operator int() const { - return m_operation; + if (m_operation == -1) { + throw std::logic_error("Unsupported audit rule condition operation!"); } + } + + operator int() const { + return m_operation; + } + + operator std::string() const { + return s_operations.find(m_operation)->second; + } - operator std::string() const { - return s_operations.find(m_operation)->second; + friend bool operator ==(const Operation& lv, const Operation& rv) { + return lv.m_operation == rv.m_operation; + } + +private: + int m_operation; +}; + +/** + * @class Value + * @brief Audit rule condition value + */ +class Value +{ + class visitor : public boost::static_visitor<> + { + public: + visitor(Json::Value& value) : m_value(value) { } - friend bool operator ==(const Operation& lv, const Operation& rv) { - return lv.m_operation == rv.m_operation; + template + void operator()(T v) const { + m_value = v; } private: - int m_operation; + Json::Value& m_value; }; - /** - * @class Value - * @brief Audit rule condition value - */ - class Value - { - class visitor : public boost::static_visitor<> - { - public: - visitor(Json::Value& value) : m_value(value) { - } +public: + Value(boost::variant value) : m_value(value) { + } - template - void operator()(T v) const { - m_value = v; - } + Json::Value asJson() const { + Json::Value res; + boost::apply_visitor(visitor{res}, m_value); + return res; + } - private: - Json::Value& m_value; - }; + operator void*() const { + if (m_value.type() == typeid(int)) + return (void*)boost::get(m_value); + return (void*)boost::get(m_value).c_str(); + } - public: - Value(boost::variant value) : m_value(value) { - } + friend bool operator ==(const Value& lv, const Value& rv) { + return lv.m_value == rv.m_value; + } - Json::Value asJson() const { - Json::Value res; - boost::apply_visitor(visitor{res}, m_value); - return res; - } +private: + boost::variant m_value; +}; - friend bool operator ==(const Value& lv, const Value& rv) { - return lv.m_value == rv.m_value; - } +/** + * @class Condition + * @brief Audit rule condition + */ +struct Condition +{ + Condition(int field, int operation, boost::variant value) + : m_field(field), m_operation(operation), m_value(value) { + } + Condition(const std::string& field, const std::string& operation, boost::variant value) + : m_field(field), m_operation(operation), m_value(value) { + } - private: - boost::variant m_value; - }; + Json::Value asJson() const { + Json::Value res; + res["field"] = (std::string)m_field; + res["operator"] = (std::string)m_operation; + res["value"] = m_value.asJson(); + return res; + } - /** - * @class Condition - * @brief Audit rule condition - */ - struct Condition - { - Condition(int field, int operation, boost::variant value) - : m_field(field), m_operation(operation), m_value(value) { - } - Condition(const std::string& field, const std::string& operation, boost::variant value) - : m_field(field), m_operation(operation), m_value(value) { + friend bool operator ==(const Condition& lv, const Condition& rv) { + return (lv.m_field == rv.m_field && lv.m_operation == rv.m_operation && lv.m_value == rv.m_value); + } + + Field m_field; + Operation m_operation; + Value m_value; +}; + +/** + * @class ConditionList + * @brief List of audit rule conditions + */ +class ConditionList : public std::list +{ +public: + Json::Value asJson() const { + Json::Value res(Json::arrayValue); + for (const auto& i : *this) { + res.append(i.asJson()); } + return res; + } +}; - Json::Value asJson() const { - Json::Value res; - res["field"] = (std::string)m_field; - res["operator"] = (std::string)m_operation; - res["value"] = m_value.asJson(); - return res; +/** + * @class RuleData + * @brief Audit rule data + */ +struct RuleData +{ + RuleData() : m_key(), m_syscall{}, m_condition{} { + } + RuleData(const Json::Value& data) : m_key(), m_syscall{}, m_condition{} { + if (data.empty()) { + throw std::logic_error("Empty rule!"); } - friend bool operator ==(const Condition& lv, const Condition& rv) { - return (lv.m_field == rv.m_field && lv.m_operation == rv.m_operation && lv.m_value == rv.m_value); + m_key = data.get("key", "").asString(); + if (m_key == "") { + throw std::logic_error("Field \"key\" is undefined!"); } - Field m_field; - Operation m_operation; - Value m_value; - }; + const Json::Value& syscall = data["syscall"]; + for (const Json::Value& v : syscall) { + m_syscall.insert(v.asInt()); + } - /** - * @class ConditionList - * @brief List of audit rule conditions - */ - class ConditionList : public std::list - { - public: - Json::Value asJson() const { - Json::Value res(Json::arrayValue); - for (const auto& i : *this) { - res.append(i.asJson()); + const Json::Value& condition = data["condition"]; + for (const Json::Value& node : condition) { + if (!node.isMember("field") || !node.isMember("operator") || !node.isMember("value")) { + throw std::logic_error("Invalid condition format!"); + } + std::string f = node.get("field", "").asString(); + std::string o = node.get("operator", "").asString(); + Json::Value v = node.get("value", Json::Value::null); + if (v.isInt()) { + m_condition.emplace_back(Condition(f,o,v.asInt())); + } else { + m_condition.emplace_back(Condition(f,o,v.asString())); } - return res; } - }; + } + + Json::Value asJson() const { + Json::Value res; + res["key"] = m_key; + res["syscall"] = m_syscall.asJson(); + res["condition"] = m_condition.asJson(); + return res; + } + + friend bool operator ==(const RuleData& lv, const RuleData& rv) { + return (lv.m_key == rv.m_key && lv.m_syscall == rv.m_syscall && lv.m_condition == rv.m_condition); + } + + std::string m_key; + SyscallArray m_syscall; + ConditionList m_condition; +}; +/** + * @class Rule + * @brief Audit rule representation + */ +class Rule +{ /** * @brief Audit rule syscall iteration callback * @details Called from audit_rule_foreach_systemcall for each syscall @@ -266,7 +328,7 @@ public: */ Rule(const std::string& key); Rule(audit_rule_h handle); - Rule(const Json::Value& rule); + Rule(const RuleData& data); /** * @brief Destructor @@ -296,21 +358,6 @@ public: */ int addCondition(const std::string& field, const std::string& operation, int value); int addCondition(const std::string& field, const std::string& operation, const std::string& value); -// template -// int addCondition(const std::string& field, const std::string& operation, T value) { -// int res = 0; - -// if (m_condition.find(field) == m_condition.end()) { -// Field f{field}; -// Operation o{operation}; -// if ((res = audit_rule_add_condition(m_handle, f, o, (void*)value)) == AUDIT_TRAIL_ERROR_NONE) { -//// m_condition.emplace(field,{field,operation,value}); -// conditionCallback(f, o, (const void*)value, &m_condition); -// } -// } - -// return res; -// } /** * @brief Remove condition from the rule @@ -321,27 +368,13 @@ public: */ int removeCondition(const std::string& field, const std::string& operation, int value); int removeCondition(const std::string& field, const std::string& operation, const std::string& value); -// template -// int removeCondition(const std::string& field, const std::string& operation, T value) { -// int res = 0; - -// if (m_condition.find(field) != m_condition.end()) { -// Field f{field}; -// Operation o{operation}; -// if ((res = audit_rule_remove_condition(m_handle, f, o, (void*)value)) == AUDIT_TRAIL_ERROR_NONE) { -// m_condition.erase(field); -// } -// } - -// return res; -// } - Json::Value asJson() const { - Json::Value res; - res["key"] = m_key; - res["syscall"] = m_syscall.asJson(); - res["condition"] = m_condition.asJson(); - return res; + /** + * @brief Get rule data + * @return data associated with the rule + */ + const RuleData& data() const { + return m_data; } operator audit_rule_h () const { @@ -349,15 +382,12 @@ public: } friend bool operator ==(const Rule& lv, const Rule& rv) { - return (lv.m_key == rv.m_key && lv.m_syscall == rv.m_syscall && lv.m_condition == rv.m_condition); + return (lv.m_handle == rv.m_handle && lv.m_data == rv.m_data); } private: - bool m_destroy_handle; audit_rule_h m_handle; - std::string m_key; - SyscallArray m_syscall; - ConditionList m_condition; + RuleData m_data; }; } //namespace audit diff --git a/device-agent/daemon/audit/rule_manager.cpp b/device-agent/daemon/audit/rule_manager.cpp index 64e8102..4c16581 100644 --- a/device-agent/daemon/audit/rule_manager.cpp +++ b/device-agent/daemon/audit/rule_manager.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -66,10 +67,10 @@ Json::Value RuleManager::getRules() Json::Value data(Json::arrayValue); for (audit_rule_h handle : ruls) { Rule rule(handle); - data.append(rule.asJson()); + data.append(rule.data().asJson()); } res["data"] = data; - } catch (std::exception& e) { + } catch (const std::exception& e) { LOG_E(TAG, "AuditRuleManager::getRules failed: %s", e.what()); return Json::Value{}; } @@ -77,6 +78,70 @@ Json::Value RuleManager::getRules() return res; } +bool RuleManager::updateRules(const Json::Value& ruls) +{ + LOG_D(TAG, "AuditRuleManager::updateRules"); + + if (ruls.get("type", "").asString() != "rule" || !ruls.isMember("data")) { + LOG_E(TAG, "AuditRuleManager::updateRules: invalid rule format"); + return false; + } + + try { + std::vector existing_ruls; + AuditRules rls = rules(); + for (audit_rule_h handle : rls) { + existing_ruls.emplace_back(handle); + } + + std::vector er_data; + for (const Rule& r : existing_ruls) { + er_data.push_back(r.data()); + } + std::vector nr_data; + const Json::Value& data = ruls["data"]; + for (const Json::Value& node : data) { + nr_data.emplace_back(node); + } + + std::vector to_remove; + for (const RuleData& v : er_data) { + if (std::find(nr_data.cbegin(),nr_data.cend(),v) == nr_data.cend()) { + to_remove.push_back(v); + } + } + + std::vector to_add; + for (const RuleData& v : nr_data) { + if (std::find(er_data.cbegin(),er_data.cend(),v) == er_data.cend()) { + to_add.push_back(v); + } + } + + for (const RuleData& v : to_remove) { + for (const Rule& r : existing_ruls) { + if (v == r.data()) { + if (audit_trail_remove_rule(m_audit_trail, r) != AUDIT_TRAIL_ERROR_NONE) { + throw std::runtime_error("audit_trail_remove_rule failed!"); + } + break; + } + } + } + + for (const RuleData& v : to_add) { + if (audit_trail_add_rule(m_audit_trail, Rule(v)) != AUDIT_TRAIL_ERROR_NONE) { + throw std::runtime_error("audit_trail_add_rule failed!"); + } + } + } catch (const std::exception& e) { + LOG_E(TAG, "AuditRuleManager::updateRules failed: %s", e.what()); + return false; + } + + return true; +} + AuditRules RuleManager::rules() { AuditRules res; diff --git a/device-agent/daemon/audit/rule_manager.h b/device-agent/daemon/audit/rule_manager.h index de07a88..884e8d8 100644 --- a/device-agent/daemon/audit/rule_manager.h +++ b/device-agent/daemon/audit/rule_manager.h @@ -61,6 +61,13 @@ public: */ Json::Value getRules(); + /** + * @brief Update all existing rules + * @param rules [in] rules to apply + * @return true/false + */ + bool updateRules(const Json::Value& ruls); + private: /** * @brief Constructor diff --git a/device-agent/utest/test_rule.cpp b/device-agent/utest/test_rule.cpp index 948ebe3..a2efdeb 100644 --- a/device-agent/utest/test_rule.cpp +++ b/device-agent/utest/test_rule.cpp @@ -37,9 +37,9 @@ protected: TEST_F(TestRule, test_parse_json) { Rule rule_1(value_1); - ASSERT_TRUE(rule_1.asJson() == value_1); + ASSERT_TRUE(rule_1.data().asJson() == value_1); Rule rule_2(value_2); - ASSERT_TRUE(rule_2.asJson() == value_2); + ASSERT_TRUE(rule_2.data().asJson() == value_2); } TEST_F(TestRule, test_add_to_rule) @@ -49,11 +49,10 @@ TEST_F(TestRule, test_add_to_rule) rule_1.addSyscall(4); rule_1.addCondition("watch", "equal", "/tmp/asd.txt"); rule_1.addCondition("perm", "equal", "rwx"); - ASSERT_TRUE(rule_1.asJson() == value_2); + ASSERT_TRUE(rule_1.data().asJson() == value_2); Rule rule_2(value_2); - ASSERT_TRUE(rule_1 == rule_2); - ASSERT_TRUE(rule_1.asJson() == rule_2.asJson()); + ASSERT_TRUE(rule_1.data().asJson() == rule_2.data().asJson()); } TEST_F(TestRule, test_remove_from_rule) @@ -63,10 +62,9 @@ TEST_F(TestRule, test_remove_from_rule) rule_2.removeSyscall(4); rule_2.removeCondition("watch", "equal", "/tmp/asd.txt"); rule_2.removeCondition("perm", "equal", "rwx"); - ASSERT_TRUE(rule_2.asJson() == value_1); + ASSERT_TRUE(rule_2.data().asJson() == value_1); Rule rule_1(value_1); - ASSERT_TRUE(rule_1 == rule_2); - ASSERT_TRUE(rule_1.asJson() == rule_2.asJson()); + ASSERT_TRUE(rule_1.data().asJson() == rule_2.data().asJson()); } #endif -- 2.7.4