Improve rule parsing, fix bugs (#28)
This commit is contained in:
Родитель
7b8b09d5d4
Коммит
dbe2bd2c78
277
AuditRules.cpp
277
AuditRules.cpp
|
@ -20,6 +20,7 @@
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
#include "KernelInfo.h"
|
#include "KernelInfo.h"
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
|
#include "UserDB.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -28,6 +29,8 @@
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
// Character that seperates key in AUDIT_FILTERKEY field in rules
|
// Character that seperates key in AUDIT_FILTERKEY field in rules
|
||||||
#define KEY_SEP 0x01
|
#define KEY_SEP 0x01
|
||||||
|
@ -216,11 +219,13 @@ bool AuditRule::Parse(const std::string& text, std::string& error) {
|
||||||
if (!parse_add_p_arg(args[idx+1], error)) {
|
if (!parse_add_p_arg(args[idx+1], error)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
idx += 2;
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
if (!parse_add_k_arg(args[idx+1], error)) {
|
if (!parse_add_k_arg(args[idx+1], error)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
idx += 2;
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
if (watch) {
|
if (watch) {
|
||||||
|
@ -236,6 +241,7 @@ bool AuditRule::Parse(const std::string& text, std::string& error) {
|
||||||
if (!parse_add_S_arg(args[idx+1], error)) {
|
if (!parse_add_S_arg(args[idx+1], error)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
idx += 2;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
if (watch) {
|
if (watch) {
|
||||||
|
@ -244,8 +250,16 @@ bool AuditRule::Parse(const std::string& text, std::string& error) {
|
||||||
error.append("' option");
|
error.append("' option");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!parse_add_F_arg(args[idx+1], error)) {
|
if (args[idx].size() > 2) {
|
||||||
return false;
|
if (!parse_add_F_arg(args[idx].substr(2), error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
} else {
|
||||||
|
if (!parse_add_F_arg(args[idx+1], error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
idx += 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
|
@ -258,6 +272,7 @@ bool AuditRule::Parse(const std::string& text, std::string& error) {
|
||||||
if (!parse_add_C_arg(args[idx+1], error)) {
|
if (!parse_add_C_arg(args[idx+1], error)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
idx += 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error.append("Unsupported option '");
|
error.append("Unsupported option '");
|
||||||
|
@ -265,7 +280,6 @@ bool AuditRule::Parse(const std::string& text, std::string& error) {
|
||||||
error.append("'");
|
error.append("'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
idx += 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -302,28 +316,32 @@ bool AuditRule::parse_add_a_arg(const std::string& val, std::string& error) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool action_found = false;
|
||||||
for (auto& part: parts) {
|
for (auto& part: parts) {
|
||||||
auto itr = s_a_actions.find(part);
|
auto itr = s_a_actions.find(part);
|
||||||
if (itr != s_a_actions.end()) {
|
if (itr != s_a_actions.end()) {
|
||||||
ruleptr()->action = itr->second;
|
ruleptr()->action = itr->second;
|
||||||
|
action_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ruleptr()->action == 0) {
|
if (!action_found) {
|
||||||
error.append("Invalid or missing action value for option '-a': '");
|
error.append("Invalid or missing action value for option '-a': '");
|
||||||
error.append(val);
|
error.append(val);
|
||||||
error.append("'");
|
error.append("'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool flags_found = false;
|
||||||
for (auto& part: parts) {
|
for (auto& part: parts) {
|
||||||
auto itr = s_a_flags.find(part);
|
auto itr = s_a_flags.find(part);
|
||||||
if (itr != s_a_flags.end()) {
|
if (itr != s_a_flags.end()) {
|
||||||
ruleptr()->flags |= itr->second;
|
ruleptr()->flags |= itr->second;
|
||||||
|
flags_found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ruleptr()->flags == 0) {
|
if (!flags_found) {
|
||||||
error.append("Invalid or missing flags value for option '-a': '");
|
error.append("Invalid or missing flags value for option '-a': '");
|
||||||
error.append(val);
|
error.append(val);
|
||||||
error.append("'");
|
error.append("'");
|
||||||
|
@ -422,6 +440,18 @@ std::unordered_map<std::string, uint32_t> s_F_ops(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, uint32_t> s_F_ftypes(
|
||||||
|
{
|
||||||
|
{"socket", S_IFSOCK},
|
||||||
|
{"link", S_IFLNK},
|
||||||
|
{"file", S_IFREG},
|
||||||
|
{"block", S_IFBLK},
|
||||||
|
{"dir", S_IFDIR},
|
||||||
|
{"character", S_IFCHR},
|
||||||
|
{"fifo", S_IFIFO},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
||||||
auto idx = val.find_first_of("=!<>&");
|
auto idx = val.find_first_of("=!<>&");
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
|
@ -474,6 +504,128 @@ bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (field) {
|
switch (field) {
|
||||||
|
case AUDIT_UID:
|
||||||
|
case AUDIT_EUID:
|
||||||
|
case AUDIT_SUID:
|
||||||
|
case AUDIT_FSUID:
|
||||||
|
case AUDIT_LOGINUID:
|
||||||
|
case AUDIT_OBJ_UID:
|
||||||
|
try {
|
||||||
|
if (std::isdigit(value[0])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else {
|
||||||
|
if (value == "unset") {
|
||||||
|
add_field(field, op, 4294967295);
|
||||||
|
} else {
|
||||||
|
auto uid = UserDB::UserNameToUid(value);
|
||||||
|
if (uid < 0) {
|
||||||
|
error.append("Invalid value for option '-F': Unknown username: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_field(field, op, uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (std::exception &) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid numeric value: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AUDIT_GID:
|
||||||
|
case AUDIT_EGID:
|
||||||
|
case AUDIT_SGID:
|
||||||
|
case AUDIT_FSGID:
|
||||||
|
case AUDIT_OBJ_GID:
|
||||||
|
try {
|
||||||
|
if (std::isdigit(value[0])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else {
|
||||||
|
if (value == "unset") {
|
||||||
|
add_field(field, op, 4294967295);
|
||||||
|
} else {
|
||||||
|
auto gid = UserDB::GroupNameToGid(value);
|
||||||
|
if (gid < 0) {
|
||||||
|
error.append("Invalid value for option '-F': Unknown group name: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_field(field, op, gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (std::exception &) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid numeric value: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AUDIT_EXIT:
|
||||||
|
if ((ruleptr()->flags & FILTER_MASK) != AUDIT_FILTER_EXIT) {
|
||||||
|
error.append("Invalid value for option '-F': Cannot filter on exit field unless flags (-a option) == 'exit'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (std::isdigit(value[0])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else if (value.size() > 1 && value[0] == '-' && std::isdigit(value[1])) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} else {
|
||||||
|
auto v = NameToErrno(value);
|
||||||
|
if (v == 0) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid errno name: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_field(field, op, v);
|
||||||
|
}
|
||||||
|
} catch (std::exception &) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid numeric value: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AUDIT_MSGTYPE:
|
||||||
|
if ((ruleptr()->flags & FILTER_MASK) != AUDIT_FILTER_TYPE) {
|
||||||
|
error.append("Invalid value for option '-F': Cannot filter on msg type unless flags (-a option) == 'exclude'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (std::isdigit(value[0])) {
|
||||||
|
try {
|
||||||
|
uint32_t v = static_cast<uint32_t>(stoul(value, 0, 0));
|
||||||
|
add_field(field, op, v);
|
||||||
|
} catch (std::exception &) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid numeric value: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto rt = RecordNameToType(value);
|
||||||
|
if (rt == RecordType::UNKNOWN) {
|
||||||
|
error.append("Invalid value for option '-F': Invalid record type name: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_field(field, op, static_cast<uint32_t>(rt));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AUDIT_ARCH: {
|
case AUDIT_ARCH: {
|
||||||
auto arch = ArchNameToArch(value);
|
auto arch = ArchNameToArch(value);
|
||||||
if (arch == 0) {
|
if (arch == 0) {
|
||||||
|
@ -489,12 +641,6 @@ bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
||||||
add_field(field, op, arch);
|
add_field(field, op, arch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AUDIT_MSGTYPE:
|
|
||||||
if ((ruleptr()->flags & FILTER_MASK) != AUDIT_FILTER_TYPE) {
|
|
||||||
error.append("Invalid value for option '-F': Cannot filter on msg type unless flags (-a option) == 'exclude'");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AUDIT_PERM: {
|
case AUDIT_PERM: {
|
||||||
uint32_t perms = 0;
|
uint32_t perms = 0;
|
||||||
for (auto c: value) {
|
for (auto c: value) {
|
||||||
|
@ -521,11 +667,29 @@ bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
||||||
add_field(AUDIT_PERM, op, perms);
|
add_field(AUDIT_PERM, op, perms);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AUDIT_OBJ_USER:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_OBJ_ROLE:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_OBJ_TYPE:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_OBJ_LEV_LOW:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_OBJ_LEV_HIGH:
|
||||||
|
if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
|
||||||
|
error = "Field '" + field_name + "' can only be used with 'exit' filter";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_str_field(field, op, value);
|
||||||
|
break;
|
||||||
case AUDIT_WATCH:
|
case AUDIT_WATCH:
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case AUDIT_DIR: {
|
case AUDIT_DIR: {
|
||||||
/* fallthrough */
|
if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
|
||||||
auto path = clean_path(val);
|
error = "Field '" + field_name + "' can only be used with 'exit' filter";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto path = clean_path(value);
|
||||||
if (!check_path(path, error)) {
|
if (!check_path(path, error)) {
|
||||||
error = "Invalid path option: " + error;
|
error = "Invalid path option: " + error;
|
||||||
return false;
|
return false;
|
||||||
|
@ -533,12 +697,38 @@ bool AuditRule::parse_add_F_arg(const std::string& val, std::string& error) {
|
||||||
add_str_field(field, op, path);
|
add_str_field(field, op, path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AUDIT_SUBJ_USER:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_SUBJ_ROLE:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_SUBJ_TYPE:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_SUBJ_SEN:
|
||||||
|
/* fallthrough */
|
||||||
|
case AUDIT_SUBJ_CLR:
|
||||||
|
/* fallthrough */
|
||||||
case AUDIT_EXE:
|
case AUDIT_EXE:
|
||||||
add_str_field(field, op, value);
|
add_str_field(field, op, value);
|
||||||
break;
|
break;
|
||||||
case AUDIT_FILTERKEY:
|
case AUDIT_FILTERKEY:
|
||||||
AddKey(value);
|
AddKey(value);
|
||||||
break;
|
break;
|
||||||
|
case AUDIT_FILETYPE: {
|
||||||
|
if (ruleptr()->flags != AUDIT_FILTER_EXIT) {
|
||||||
|
error = "Field '" + field_name + "' can only be used with 'exit' filter";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto ft = s_F_ftypes.find(value);
|
||||||
|
if (ft != s_F_ftypes.end()) {
|
||||||
|
add_field(field, op, ft->second);
|
||||||
|
} else {
|
||||||
|
error.append("Invalid value for option '-F': Invalid filetype name: '");
|
||||||
|
error.append(val);
|
||||||
|
error.append("'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
try {
|
try {
|
||||||
uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
|
uint32_t v = static_cast<uint32_t>(stol(value, 0, 0));
|
||||||
|
@ -1689,7 +1879,7 @@ void RemoveSection(std::vector<std::string>& lines, const std::string& start_mar
|
||||||
lines.erase(start, end);
|
lines.erase(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AuditRule> ParseRules(const std::vector<std::string>& lines) {
|
std::vector<AuditRule> ParseRules(const std::vector<std::string>& lines, std::vector<std::string>* errors) {
|
||||||
std::vector<AuditRule> rules;
|
std::vector<AuditRule> rules;
|
||||||
for (int i = 0; i < lines.size(); ++i) {
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
AuditRule rule;
|
AuditRule rule;
|
||||||
|
@ -1697,7 +1887,11 @@ std::vector<AuditRule> ParseRules(const std::vector<std::string>& lines) {
|
||||||
if (rule.Parse(lines[i], error)) {
|
if (rule.Parse(lines[i], error)) {
|
||||||
rules.emplace_back(rule);
|
rules.emplace_back(rule);
|
||||||
} else if (!error.empty()) {
|
} else if (!error.empty()) {
|
||||||
throw std::runtime_error("Failed to parse line " + std::to_string(i+1) + ": " + error);
|
if (errors != nullptr) {
|
||||||
|
errors->emplace_back("Failed to parse line " + std::to_string(i + 1) + ": " + error);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Failed to parse line " + std::to_string(i + 1) + ": " + error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rules;
|
return rules;
|
||||||
|
@ -1827,7 +2021,7 @@ std::vector<AuditRule> DiffRules(const std::vector<AuditRule>& actual, const std
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir) {
|
std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir, std::vector<std::string>* errors) {
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
std::vector<AuditRule> rules;
|
std::vector<AuditRule> rules;
|
||||||
|
|
||||||
|
@ -1836,7 +2030,7 @@ std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir) {
|
||||||
for(auto& file: files) {
|
for(auto& file: files) {
|
||||||
if (ends_with(file, ".rules")) {
|
if (ends_with(file, ".rules")) {
|
||||||
auto lines = ReadFile(dir + "/" + file);
|
auto lines = ReadFile(dir + "/" + file);
|
||||||
rules = MergeRules(rules, ParseRules(lines));
|
rules = MergeRules(rules, ParseRules(lines, errors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,7 +2038,7 @@ std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read rules from auditd rules.d dir
|
// Read rules from auditd rules.d dir
|
||||||
std::vector<AuditRule> ReadAuditdRulesDir(bool exclude_auoms) {
|
std::vector<AuditRule> ReadAuditdRulesDir(bool exclude_auoms, std::vector<std::string>* errors) {
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
std::vector<AuditRule> rules;
|
std::vector<AuditRule> rules;
|
||||||
|
|
||||||
|
@ -1853,8 +2047,9 @@ std::vector<AuditRule> ReadAuditdRulesDir(bool exclude_auoms) {
|
||||||
for(auto& file: files) {
|
for(auto& file: files) {
|
||||||
if (ends_with(file, ".rules")) {
|
if (ends_with(file, ".rules")) {
|
||||||
auto lines = ReadFile(std::string(AUDITD_RULES_DIR) + "/" + file);
|
auto lines = ReadFile(std::string(AUDITD_RULES_DIR) + "/" + file);
|
||||||
|
std::vector<std::string> file_errors;
|
||||||
if (exclude_auoms) {
|
if (exclude_auoms) {
|
||||||
auto in_rules = ParseRules(lines);
|
auto in_rules = ParseRules(lines, &file_errors);
|
||||||
std::vector<AuditRule> out_rules;
|
std::vector<AuditRule> out_rules;
|
||||||
out_rules.reserve(in_rules.size());
|
out_rules.reserve(in_rules.size());
|
||||||
// Only include non-auoms rules
|
// Only include non-auoms rules
|
||||||
|
@ -1866,7 +2061,19 @@ std::vector<AuditRule> ReadAuditdRulesDir(bool exclude_auoms) {
|
||||||
}
|
}
|
||||||
rules = MergeRules(rules, out_rules);
|
rules = MergeRules(rules, out_rules);
|
||||||
} else {
|
} else {
|
||||||
rules = MergeRules(rules, ParseRules(lines));
|
rules = MergeRules(rules, ParseRules(lines, &file_errors));
|
||||||
|
}
|
||||||
|
if (errors != nullptr) {
|
||||||
|
for (auto &err : file_errors) {
|
||||||
|
errors->emplace_back("Encountered parse error in '" + std::string(AUDITD_RULES_DIR) + "/" + file + "': " + err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Encountered parse errors in '" << std::string(AUDITD_RULES_DIR) << "/" << file << "': " << std::endl;
|
||||||
|
for (auto &err : file_errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1908,7 +2115,7 @@ bool HasAuditdRulesFiles() {
|
||||||
return PathExists(AUDITD_RULES_FILE);
|
return PathExists(AUDITD_RULES_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms) {
|
std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms, std::vector<std::string>* errors) {
|
||||||
if (!PathExists(AUDITD_RULES_FILE)) {
|
if (!PathExists(AUDITD_RULES_FILE)) {
|
||||||
return std::vector<AuditRule>();
|
return std::vector<AuditRule>();
|
||||||
}
|
}
|
||||||
|
@ -1918,13 +2125,15 @@ std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms) {
|
||||||
// If the audit.rules file was at any time in the past generated with augenrules
|
// If the audit.rules file was at any time in the past generated with augenrules
|
||||||
// assume it is still in use
|
// assume it is still in use
|
||||||
if (PathExists(AUGENRULES_BIN) && lines.size() > 0 && starts_with(lines[0], AUGENRULES_HEADER)) {
|
if (PathExists(AUGENRULES_BIN) && lines.size() > 0 && starts_with(lines[0], AUGENRULES_HEADER)) {
|
||||||
return ReadAuditdRulesDir(exclude_auoms);
|
return ReadAuditdRulesDir(exclude_auoms, errors);
|
||||||
} else {
|
} else {
|
||||||
|
std::vector<AuditRule> rules;
|
||||||
|
std::vector<std::string> file_errors;
|
||||||
if (exclude_auoms) {
|
if (exclude_auoms) {
|
||||||
// Remove the auoms rules section if present.
|
// Remove the auoms rules section if present.
|
||||||
RemoveSection(lines, AUOMS_AUDITD_RULES_FILE_START_MARKER, AUOMS_AUDITD_RULES_FILE_END_MARKER);
|
RemoveSection(lines, AUOMS_AUDITD_RULES_FILE_START_MARKER, AUOMS_AUDITD_RULES_FILE_END_MARKER);
|
||||||
|
|
||||||
auto in_rules = ParseRules(lines);
|
auto in_rules = ParseRules(lines, &file_errors);
|
||||||
std::vector<AuditRule> out_rules;
|
std::vector<AuditRule> out_rules;
|
||||||
out_rules.reserve(in_rules.size());
|
out_rules.reserve(in_rules.size());
|
||||||
// Only include non-auoms rules
|
// Only include non-auoms rules
|
||||||
|
@ -1934,17 +2143,30 @@ std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms) {
|
||||||
out_rules.emplace_back(rule);
|
out_rules.emplace_back(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MergeRules({}, out_rules);
|
rules = MergeRules({}, out_rules);
|
||||||
} else {
|
} else {
|
||||||
return MergeRules({}, ParseRules(lines));
|
rules = MergeRules({}, ParseRules(lines, &file_errors));
|
||||||
}
|
}
|
||||||
|
if (errors != nullptr) {
|
||||||
|
for (auto &err : file_errors) {
|
||||||
|
errors->emplace_back("Encountered parse error in '" + std::string(AUDITD_RULES_FILE) + "': " + err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Encountered parse errors in '" << std::string(AUDITD_RULES_FILE) << "': " << std::endl;
|
||||||
|
for (auto &err : file_errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
throw std::runtime_error(ss.str());
|
||||||
|
}
|
||||||
|
return rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteAuditdRules(const std::vector<AuditRule>& rules) {
|
bool WriteAuditdRules(const std::vector<AuditRule>& rules) {
|
||||||
auto lines = ReadFile(AUDITD_RULES_FILE);
|
auto lines = ReadFile(AUDITD_RULES_FILE);
|
||||||
|
|
||||||
if (PathExists(AUGENRULES_BIN) && lines.size() > 0 && starts_with(lines[0], AUGENRULES_HEADER)) {
|
if (PathExists(AUGENRULES_BIN) && !lines.empty() && starts_with(lines[0], AUGENRULES_HEADER)) {
|
||||||
WriteAuomsRuleToAuditDir(rules);
|
WriteAuomsRuleToAuditDir(rules);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1960,8 +2182,9 @@ bool WriteAuditdRules(const std::vector<AuditRule>& rules) {
|
||||||
// Remove auoms's desired rules to auditd config
|
// Remove auoms's desired rules to auditd config
|
||||||
// Returns true if augenrules needs to be run
|
// Returns true if augenrules needs to be run
|
||||||
bool RemoveAuomsRulesAuditdFiles() {
|
bool RemoveAuomsRulesAuditdFiles() {
|
||||||
|
std::vector<std::string> errors;
|
||||||
bool has_auoms_rules = false;
|
bool has_auoms_rules = false;
|
||||||
auto rules = ReadActualAuditdRules(false);
|
auto rules = ReadActualAuditdRules(false, &errors);
|
||||||
for (auto &rule: rules) {
|
for (auto &rule: rules) {
|
||||||
auto keys = rule.GetKeys();
|
auto keys = rule.GetKeys();
|
||||||
if (keys.count(AUOMS_RULE_KEY) > 0) {
|
if (keys.count(AUOMS_RULE_KEY) > 0) {
|
||||||
|
|
12
AuditRules.h
12
AuditRules.h
|
@ -141,6 +141,9 @@ public:
|
||||||
|
|
||||||
AuditRule(const void* data, size_t len): _data(), _value_offsets(), is_delete_rule(false) {
|
AuditRule(const void* data, size_t len): _data(), _value_offsets(), is_delete_rule(false) {
|
||||||
_data.fill(0);
|
_data.fill(0);
|
||||||
|
if (len > _data.size()) {
|
||||||
|
throw std::out_of_range("len too large");
|
||||||
|
}
|
||||||
::memcpy(_data.data(), data, len);
|
::memcpy(_data.data(), data, len);
|
||||||
fill_value_offsets();
|
fill_value_offsets();
|
||||||
}
|
}
|
||||||
|
@ -240,7 +243,10 @@ private:
|
||||||
|
|
||||||
void ReplaceSection(std::vector<std::string>& lines, const std::vector<std::string>& replacement, const std::string& start_marker, const std::string& end_marker);
|
void ReplaceSection(std::vector<std::string>& lines, const std::vector<std::string>& replacement, const std::string& start_marker, const std::string& end_marker);
|
||||||
void RemoveSection(std::vector<std::string>& lines, const std::string& start_marker, const std::string& end_marker);
|
void RemoveSection(std::vector<std::string>& lines, const std::string& start_marker, const std::string& end_marker);
|
||||||
std::vector<AuditRule> ParseRules(const std::vector<std::string>& lines);
|
|
||||||
|
// If errors is null, then ParseRules will throiw an exception if there is a parse error
|
||||||
|
// If errors is not null, then ParseRules willa append each parse error to errors and return only the parsed rules.
|
||||||
|
std::vector<AuditRule> ParseRules(const std::vector<std::string>& lines, std::vector<std::string>* errors);
|
||||||
|
|
||||||
std::vector<AuditRule> MergeRules(const std::vector<AuditRule>& rules1);
|
std::vector<AuditRule> MergeRules(const std::vector<AuditRule>& rules1);
|
||||||
std::vector<AuditRule> MergeRules(const std::vector<AuditRule>& rules1, const std::vector<AuditRule>& rules2);
|
std::vector<AuditRule> MergeRules(const std::vector<AuditRule>& rules1, const std::vector<AuditRule>& rules2);
|
||||||
|
@ -253,10 +259,10 @@ std::vector<AuditRule> DiffRules(const std::vector<AuditRule>& actual, const std
|
||||||
bool HasAuditdRulesFiles();
|
bool HasAuditdRulesFiles();
|
||||||
|
|
||||||
// Read all *.rules files from dir, parse, merge then return them.
|
// Read all *.rules files from dir, parse, merge then return them.
|
||||||
std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir);
|
std::vector<AuditRule> ReadAuditRulesFromDir(const std::string& dir, std::vector<std::string>* errors);
|
||||||
|
|
||||||
// Read rules from auditd rules (excluding auoms rules)
|
// Read rules from auditd rules (excluding auoms rules)
|
||||||
std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms);
|
std::vector<AuditRule> ReadActualAuditdRules(bool exclude_auoms, std::vector<std::string>* errors);
|
||||||
|
|
||||||
// Adds auoms's desired rules to auditd config
|
// Adds auoms's desired rules to auditd config
|
||||||
// Returns true if augenrules needs to be run
|
// Returns true if augenrules needs to be run
|
||||||
|
|
|
@ -2,13 +2,20 @@
|
||||||
// Created by tad on 3/18/19.
|
// Created by tad on 3/18/19.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include "AuditRulesMonitor.h"
|
#include "AuditRulesMonitor.h"
|
||||||
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "ExecUtil.h"
|
#include "ExecUtil.h"
|
||||||
|
|
||||||
|
#define PREFERRED_BACKLOG_LIMIT 8192
|
||||||
|
|
||||||
|
|
||||||
void AuditRulesMonitor::run() {
|
void AuditRulesMonitor::run() {
|
||||||
Logger::Info("AuditRulesMonitor: Starting");
|
Logger::Info("AuditRulesMonitor: Starting");
|
||||||
|
|
||||||
|
check_audit_status();
|
||||||
|
|
||||||
while(!_sleep(1000)) {
|
while(!_sleep(1000)) {
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
@ -35,7 +42,8 @@ void AuditRulesMonitor::on_stop() {
|
||||||
|
|
||||||
void AuditRulesMonitor::get_desired_rules() {
|
void AuditRulesMonitor::get_desired_rules() {
|
||||||
try {
|
try {
|
||||||
auto rules = ReadAuditRulesFromDir(_audit_rules_dir);
|
std::vector<std::string> errors;
|
||||||
|
auto rules = ReadAuditRulesFromDir(_audit_rules_dir, &errors);
|
||||||
_desired_rules.resize(0);
|
_desired_rules.resize(0);
|
||||||
for (auto& rule: rules) {
|
for (auto& rule: rules) {
|
||||||
// Only include the rule in the desired rules if it is supported on the host system
|
// Only include the rule in the desired rules if it is supported on the host system
|
||||||
|
@ -44,7 +52,16 @@ void AuditRulesMonitor::get_desired_rules() {
|
||||||
_desired_rules.emplace_back(rule);
|
_desired_rules.emplace_back(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_op_status->ClearErrorCondition(ErrorCategory::DESIRED_RULES);
|
if (errors.empty()) {
|
||||||
|
_op_status->ClearErrorCondition(ErrorCategory::DESIRED_RULES);
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << " Encountered parse errors: " << std::endl;
|
||||||
|
for (auto& err : errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
_op_status->SetErrorCondition(ErrorCategory::DESIRED_RULES, ss.str());
|
||||||
|
}
|
||||||
} catch(std::exception& ex) {
|
} catch(std::exception& ex) {
|
||||||
Logger::Error("AuditRulesMonitor: Failed to read desired rules from %s: %s", _audit_rules_dir.c_str(), ex.what());
|
Logger::Error("AuditRulesMonitor: Failed to read desired rules from %s: %s", _audit_rules_dir.c_str(), ex.what());
|
||||||
_op_status->SetErrorCondition(ErrorCategory::DESIRED_RULES, "Failed to read desired rules from " + _audit_rules_dir + ": " + ex.what());
|
_op_status->SetErrorCondition(ErrorCategory::DESIRED_RULES, "Failed to read desired rules from " + _audit_rules_dir + ": " + ex.what());
|
||||||
|
@ -57,16 +74,27 @@ void AuditRulesMonitor::check_file_rules() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
auto rules = ReadActualAuditdRules(false);
|
std::vector<std::string> errors;
|
||||||
|
auto rules = ReadActualAuditdRules(false, &errors);
|
||||||
auto merged_rules = MergeRules(rules);
|
auto merged_rules = MergeRules(rules);
|
||||||
auto diff = DiffRules(merged_rules, _desired_rules, "");
|
auto diff = DiffRules(merged_rules, _desired_rules, "");
|
||||||
if (diff.empty()) {
|
if (diff.empty()) {
|
||||||
_op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_FILE);
|
if (errors.empty()) {
|
||||||
|
_op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_FILE);
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << " Encountered parse errors: " << std::endl;
|
||||||
|
for (auto& err : errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, ss.str());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger::Info("AuditRulesMonitor: Found desired audit rules not currently present in auditd rules files(s), adding new rules");
|
Logger::Info("AuditRulesMonitor: Found desired audit rules not currently present in auditd rules files(s), adding new rules");
|
||||||
// Re-read rules but exclude auoms rules
|
// Re-read rules but exclude auoms rules
|
||||||
rules = ReadActualAuditdRules(true);
|
errors.clear();
|
||||||
|
rules = ReadActualAuditdRules(true, &errors);
|
||||||
merged_rules = MergeRules(rules);
|
merged_rules = MergeRules(rules);
|
||||||
// Re-calculate diff
|
// Re-calculate diff
|
||||||
diff = DiffRules(merged_rules, _desired_rules, "");
|
diff = DiffRules(merged_rules, _desired_rules, "");
|
||||||
|
@ -78,12 +106,32 @@ void AuditRulesMonitor::check_file_rules() {
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
Logger::Warn("AuditRulesMonitor: augenrules failed: %s", cmd.FailMsg().c_str());
|
Logger::Warn("AuditRulesMonitor: augenrules failed: %s", cmd.FailMsg().c_str());
|
||||||
Logger::Warn("AuditRulesMonitor: augenrules output: %s", output.c_str());
|
Logger::Warn("AuditRulesMonitor: augenrules output: %s", output.c_str());
|
||||||
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, std::string("augenrules failed: ") + cmd.FailMsg());
|
if (errors.empty()) {
|
||||||
|
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, std::string("augenrules failed: ") + cmd.FailMsg());
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << " Encountered parse errors and augenrules failed: " << std::endl;
|
||||||
|
ss << " augenrules error:" << cmd.FailMsg() << std::endl;
|
||||||
|
for (auto& err : errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, ss.str());
|
||||||
|
}
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
Logger::Warn("AuditRulesMonitor: augenrules succeeded");
|
Logger::Warn("AuditRulesMonitor: augenrules succeeded");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_FILE);
|
if (errors.empty()) {
|
||||||
|
_op_status->ClearErrorCondition(ErrorCategory::AUDIT_RULES_FILE);
|
||||||
|
} else {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << " Encountered parse errors: " << std::endl;
|
||||||
|
for (auto& err : errors) {
|
||||||
|
ss << " " << err << std::endl;
|
||||||
|
}
|
||||||
|
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, ss.str());
|
||||||
|
}
|
||||||
} catch (std::exception& ex) {
|
} catch (std::exception& ex) {
|
||||||
Logger::Error("AuditRulesMonitor: Failed to check/update auditd rules: %s", ex.what());
|
Logger::Error("AuditRulesMonitor: Failed to check/update auditd rules: %s", ex.what());
|
||||||
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, std::string("Failed to check/update auditd rules: ") + ex.what());
|
_op_status->SetErrorCondition(ErrorCategory::AUDIT_RULES_FILE, std::string("Failed to check/update auditd rules: ") + ex.what());
|
||||||
|
@ -226,3 +274,26 @@ bool AuditRulesMonitor::check_kernel_rules() {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AuditRulesMonitor::check_audit_status() {
|
||||||
|
audit_status status;
|
||||||
|
auto ret = NetlinkRetry([this,&status]() { return _netlink.AuditGet(status); } );
|
||||||
|
if (ret != 0) {
|
||||||
|
Logger::Error("Failed to get audit status: %s", std::strerror(-ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status.backlog_limit < PREFERRED_BACKLOG_LIMIT) {
|
||||||
|
Logger::Error("Increasing audit backlog limit from %u to %u", status.backlog_limit, PREFERRED_BACKLOG_LIMIT);
|
||||||
|
ret = NetlinkRetry([this]() {
|
||||||
|
audit_status status;
|
||||||
|
::memset(&status, 0, sizeof(status));
|
||||||
|
status.mask = AUDIT_STATUS_BACKLOG_LIMIT;
|
||||||
|
status.backlog_limit = PREFERRED_BACKLOG_LIMIT;
|
||||||
|
return _netlink.AuditSet(status);
|
||||||
|
});
|
||||||
|
if (ret != 0) {
|
||||||
|
Logger::Error("Failed to set audit backlog limit to %d: %s", PREFERRED_BACKLOG_LIMIT, std::strerror(-ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,7 @@ private:
|
||||||
void get_desired_rules();
|
void get_desired_rules();
|
||||||
void check_file_rules();
|
void check_file_rules();
|
||||||
bool check_kernel_rules();
|
bool check_kernel_rules();
|
||||||
|
void check_audit_status();
|
||||||
|
|
||||||
Netlink& _netlink;
|
Netlink& _netlink;
|
||||||
std::string _audit_rules_dir;
|
std::string _audit_rules_dir;
|
||||||
|
|
|
@ -113,6 +113,7 @@ add_executable(auoms
|
||||||
TranslateRecordType.cpp
|
TranslateRecordType.cpp
|
||||||
TranslateFieldType.cpp
|
TranslateFieldType.cpp
|
||||||
TranslateField.cpp
|
TranslateField.cpp
|
||||||
|
TranslateErrno.cpp
|
||||||
AuditRules.cpp
|
AuditRules.cpp
|
||||||
AuditRulesMonitor.cpp
|
AuditRulesMonitor.cpp
|
||||||
KernelInfo.cpp
|
KernelInfo.cpp
|
||||||
|
@ -155,6 +156,7 @@ add_executable(auomsctl
|
||||||
TranslateRecordType.cpp
|
TranslateRecordType.cpp
|
||||||
TranslateFieldType.cpp
|
TranslateFieldType.cpp
|
||||||
TranslateField.cpp
|
TranslateField.cpp
|
||||||
|
TranslateErrno.cpp
|
||||||
AuditRules.cpp
|
AuditRules.cpp
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
KernelInfo.cpp
|
KernelInfo.cpp
|
||||||
|
@ -165,6 +167,7 @@ add_executable(auomsctl
|
||||||
FileUtils.cpp
|
FileUtils.cpp
|
||||||
UnixDomainListener.cpp
|
UnixDomainListener.cpp
|
||||||
Event.cpp
|
Event.cpp
|
||||||
|
UserDB.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html
|
# See https://gcc.gnu.org/onlinedocs/libstdc++/manual/license.html
|
||||||
|
|
|
@ -180,8 +180,6 @@ bool CollectionMonitor::is_collector_alive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CollectionMonitor::send_audit_pid_report(int pid) {
|
void CollectionMonitor::send_audit_pid_report(int pid) {
|
||||||
Logger::Info("CollectionMonitor: Audit Pid: %d", pid);
|
|
||||||
|
|
||||||
auto pinfo = ProcessInfo::Open(pid);
|
auto pinfo = ProcessInfo::Open(pid);
|
||||||
std::string exe;
|
std::string exe;
|
||||||
int ppid = -1;
|
int ppid = -1;
|
||||||
|
|
|
@ -107,7 +107,7 @@ bool CursorWriter::Read() {
|
||||||
Logger::Error("Output(%s): Failed to open cursor file (%s): %s", _name.c_str(), _path.c_str(), std::strerror(errno));
|
Logger::Error("Output(%s): Failed to open cursor file (%s): %s", _name.c_str(), _path.c_str(), std::strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
_cursor = QueueCursor::TAIL;
|
_cursor = QueueCursor::HEAD;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ bool ProcessInfo::parse_stat() {
|
||||||
if (*ptr != '(') {
|
if (*ptr != '(') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
f_end = strchr(ptr, ')');
|
f_end = strstr(ptr, ") ");
|
||||||
if (f_end != nullptr && f_end+1 < end && f_end[1] == ')') {
|
if (f_end != nullptr && f_end+1 < end && f_end[1] == ')') {
|
||||||
f_end += 1;
|
f_end += 1;
|
||||||
}
|
}
|
||||||
|
|
15
Queue.cpp
15
Queue.cpp
|
@ -294,8 +294,13 @@ void Queue::Close(bool save)
|
||||||
save_locked(lock);
|
save_locked(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for any active save to complete
|
||||||
|
_cond.wait(lock, [this]() { return !_save_active; });
|
||||||
|
|
||||||
close(_fd);
|
close(_fd);
|
||||||
_fd = -1;
|
_fd = -1;
|
||||||
|
|
||||||
|
_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::Save() {
|
void Queue::Save() {
|
||||||
|
@ -329,8 +334,6 @@ void Queue::save_locked(std::unique_lock<std::mutex>& lock)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fd = _fd;
|
|
||||||
|
|
||||||
_save_active = true;
|
_save_active = true;
|
||||||
|
|
||||||
FileHeader before;
|
FileHeader before;
|
||||||
|
@ -393,20 +396,22 @@ void Queue::save_locked(std::unique_lock<std::mutex>& lock)
|
||||||
int64_t save_size = 0;
|
int64_t save_size = 0;
|
||||||
|
|
||||||
if (nregions > 0) {
|
if (nregions > 0) {
|
||||||
_pwrite(fd, &before, sizeof(FileHeader), 0);
|
_pwrite(_fd, &before, sizeof(FileHeader), 0);
|
||||||
|
|
||||||
for (int i = 0; i < nregions; i++) {
|
for (int i = 0; i < nregions; i++) {
|
||||||
_pwrite(fd, regions[i].data, regions[i].size, regions[i].index);
|
_pwrite(_fd, regions[i].data, regions[i].size, regions[i].index);
|
||||||
save_size += regions[i].size;
|
save_size += regions[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_pwrite(fd, &after, sizeof(FileHeader), 0);
|
_pwrite(_fd, &after, sizeof(FileHeader), 0);
|
||||||
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
|
|
||||||
_saved_size += save_size;
|
_saved_size += save_size;
|
||||||
_save_active = false;
|
_save_active = false;
|
||||||
|
|
||||||
|
_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes queue is locked
|
// Assumes queue is locked
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
std::atomic<bool> Signals::_exit(false);
|
std::atomic<bool> Signals::_exit(false);
|
||||||
|
std::mutex Signals::_mutex;
|
||||||
std::function<void()> Signals::_hup_fn;
|
std::function<void()> Signals::_hup_fn;
|
||||||
std::function<void()> Signals::_exit_fn;
|
std::function<void()> Signals::_exit_fn;
|
||||||
pthread_t Signals::_main_id;
|
pthread_t Signals::_main_id;
|
||||||
|
@ -106,13 +107,17 @@ void Signals::run() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sig == SIGHUP) {
|
if (sig == SIGHUP) {
|
||||||
|
std::lock_guard<std::mutex> _lock(_mutex);
|
||||||
if (_hup_fn) {
|
if (_hup_fn) {
|
||||||
_hup_fn();
|
_hup_fn();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_exit.store(true);
|
_exit.store(true);
|
||||||
if (_exit_fn) {
|
{
|
||||||
_exit_fn();
|
std::lock_guard<std::mutex> _lock(_mutex);
|
||||||
|
if (_exit_fn) {
|
||||||
|
_exit_fn();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Break main thread out of blocking syscall
|
// Break main thread out of blocking syscall
|
||||||
pthread_kill(_main_id, SIGQUIT);
|
pthread_kill(_main_id, SIGQUIT);
|
||||||
|
|
12
Signals.h
12
Signals.h
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
@ -29,13 +30,20 @@ public:
|
||||||
static bool IsExit();
|
static bool IsExit();
|
||||||
static void Terminate();
|
static void Terminate();
|
||||||
|
|
||||||
static void SetHupHandler(std::function<void()> fn) { _hup_fn = fn; }
|
static void SetHupHandler(std::function<void()> fn) {
|
||||||
static void SetExitHandler(std::function<void()> fn) { _exit_fn = fn; }
|
std::lock_guard<std::mutex> _lock(_mutex);
|
||||||
|
_hup_fn = fn;
|
||||||
|
}
|
||||||
|
static void SetExitHandler(std::function<void()> fn) {
|
||||||
|
std::lock_guard<std::mutex> _lock(_mutex);
|
||||||
|
_exit_fn = fn;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void run();
|
static void run();
|
||||||
|
|
||||||
static std::atomic<bool> _exit;
|
static std::atomic<bool> _exit;
|
||||||
|
static std::mutex _mutex;
|
||||||
static std::function<void()> _hup_fn;
|
static std::function<void()> _hup_fn;
|
||||||
static std::function<void()> _exit_fn;
|
static std::function<void()> _exit_fn;
|
||||||
static pthread_t _main_id;
|
static pthread_t _main_id;
|
||||||
|
|
|
@ -45,4 +45,7 @@ field_type_t FieldNameToType(RecordType rtype, const std::string_view& name, con
|
||||||
std::string FieldIdToName(int field);
|
std::string FieldIdToName(int field);
|
||||||
int FieldNameToId(const std::string_view& name);
|
int FieldNameToId(const std::string_view& name);
|
||||||
|
|
||||||
|
std::string ErrnoToName(int field);
|
||||||
|
int NameToErrno(const std::string_view& name);
|
||||||
|
|
||||||
#endif //AUOMS_TRANSLATE_H
|
#endif //AUOMS_TRANSLATE_H
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
microsoft-oms-auditd-plugin
|
||||||
|
|
||||||
|
Copyright (c) Microsoft Corporation
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/audit.h>
|
||||||
|
|
||||||
|
#include "Translate.h"
|
||||||
|
#include "StringTable.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static StringTable<int> s_errno_table(0, {
|
||||||
|
{"EPERM", EPERM},
|
||||||
|
{"ENOENT", ENOENT},
|
||||||
|
{"ESRCH", ESRCH},
|
||||||
|
{"EINTR", EINTR},
|
||||||
|
{"EIO", EIO},
|
||||||
|
{"ENXIO", ENXIO},
|
||||||
|
{"E2BIG", E2BIG},
|
||||||
|
{"ENOEXEC", ENOEXEC},
|
||||||
|
{"EBADF", EBADF},
|
||||||
|
{"ECHILD", ECHILD},
|
||||||
|
{"EAGAIN", EAGAIN},
|
||||||
|
{"ENOMEM", ENOMEM},
|
||||||
|
{"EACCES", EACCES},
|
||||||
|
{"EFAULT", EFAULT},
|
||||||
|
{"ENOTBLK", ENOTBLK},
|
||||||
|
{"EBUSY", EBUSY},
|
||||||
|
{"EEXIST", EEXIST},
|
||||||
|
{"EXDEV", EXDEV},
|
||||||
|
{"ENODEV", ENODEV},
|
||||||
|
{"ENOTDIR", ENOTDIR},
|
||||||
|
{"EISDIR", EISDIR},
|
||||||
|
{"EINVAL", EINVAL},
|
||||||
|
{"ENFILE", ENFILE},
|
||||||
|
{"EMFILE", EMFILE},
|
||||||
|
{"ENOTTY", ENOTTY},
|
||||||
|
{"ETXTBSY", ETXTBSY},
|
||||||
|
{"EFBIG", EFBIG},
|
||||||
|
{"ENOSPC", ENOSPC},
|
||||||
|
{"ESPIPE", ESPIPE},
|
||||||
|
{"EROFS", EROFS},
|
||||||
|
{"EMLINK", EMLINK},
|
||||||
|
{"EPIPE", EPIPE},
|
||||||
|
{"EDOM", EDOM},
|
||||||
|
{"ERANGE", ERANGE},
|
||||||
|
{"EDEADLK", EDEADLK},
|
||||||
|
{"ENAMETOOLONG", ENAMETOOLONG},
|
||||||
|
{"ENOLCK", ENOLCK},
|
||||||
|
{"ENOSYS", ENOSYS},
|
||||||
|
{"ENOTEMPTY", ENOTEMPTY},
|
||||||
|
{"ELOOP", ELOOP},
|
||||||
|
{"EWOULDBLOCK", EWOULDBLOCK},
|
||||||
|
{"ENOMSG", ENOMSG},
|
||||||
|
{"EIDRM", EIDRM},
|
||||||
|
{"ECHRNG", ECHRNG},
|
||||||
|
{"EL2NSYNC", EL2NSYNC},
|
||||||
|
{"EL3HLT", EL3HLT},
|
||||||
|
{"EL3RST", EL3RST},
|
||||||
|
{"ELNRNG", ELNRNG},
|
||||||
|
{"EUNATCH", EUNATCH},
|
||||||
|
{"ENOCSI", ENOCSI},
|
||||||
|
{"EL2HLT", EL2HLT},
|
||||||
|
{"EBADE", EBADE},
|
||||||
|
{"EBADR", EBADR},
|
||||||
|
{"EXFULL", EXFULL},
|
||||||
|
{"ENOANO", ENOANO},
|
||||||
|
{"EBADRQC", EBADRQC},
|
||||||
|
{"EBADSLT", EBADSLT},
|
||||||
|
{"EDEADLOCK", EDEADLOCK},
|
||||||
|
{"EBFONT", EBFONT},
|
||||||
|
{"ENOSTR", ENOSTR},
|
||||||
|
{"ENODATA", ENODATA},
|
||||||
|
{"ETIME", ETIME},
|
||||||
|
{"ENOSR", ENOSR},
|
||||||
|
{"ENONET", ENONET},
|
||||||
|
{"ENOPKG", ENOPKG},
|
||||||
|
{"EREMOTE", EREMOTE},
|
||||||
|
{"ENOLINK", ENOLINK},
|
||||||
|
{"EADV", EADV},
|
||||||
|
{"ESRMNT", ESRMNT},
|
||||||
|
{"ECOMM", ECOMM},
|
||||||
|
{"EPROTO", EPROTO},
|
||||||
|
{"EMULTIHOP", EMULTIHOP},
|
||||||
|
{"EDOTDOT", EDOTDOT},
|
||||||
|
{"EBADMSG", EBADMSG},
|
||||||
|
{"EOVERFLOW", EOVERFLOW},
|
||||||
|
{"ENOTUNIQ", ENOTUNIQ},
|
||||||
|
{"EBADFD", EBADFD},
|
||||||
|
{"EREMCHG", EREMCHG},
|
||||||
|
{"ELIBACC", ELIBACC},
|
||||||
|
{"ELIBBAD", ELIBBAD},
|
||||||
|
{"ELIBSCN", ELIBSCN},
|
||||||
|
{"ELIBMAX", ELIBMAX},
|
||||||
|
{"ELIBEXEC", ELIBEXEC},
|
||||||
|
{"EILSEQ", EILSEQ},
|
||||||
|
{"ERESTART", ERESTART},
|
||||||
|
{"ESTRPIPE", ESTRPIPE},
|
||||||
|
{"EUSERS", EUSERS},
|
||||||
|
{"ENOTSOCK", ENOTSOCK},
|
||||||
|
{"EDESTADDRREQ", EDESTADDRREQ},
|
||||||
|
{"EMSGSIZE", EMSGSIZE},
|
||||||
|
{"EPROTOTYPE", EPROTOTYPE},
|
||||||
|
{"ENOPROTOOPT", ENOPROTOOPT},
|
||||||
|
{"EPROTONOSUPPORT", EPROTONOSUPPORT},
|
||||||
|
{"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT},
|
||||||
|
{"EOPNOTSUPP", EOPNOTSUPP},
|
||||||
|
{"EPFNOSUPPORT", EPFNOSUPPORT},
|
||||||
|
{"EAFNOSUPPORT", EAFNOSUPPORT},
|
||||||
|
{"EADDRINUSE", EADDRINUSE},
|
||||||
|
{"EADDRNOTAVAIL", EADDRNOTAVAIL},
|
||||||
|
{"ENETDOWN", ENETDOWN},
|
||||||
|
{"ENETUNREACH", ENETUNREACH},
|
||||||
|
{"ENETRESET", ENETRESET},
|
||||||
|
{"ECONNABORTED", ECONNABORTED},
|
||||||
|
{"ECONNRESET", ECONNRESET},
|
||||||
|
{"ENOBUFS", ENOBUFS},
|
||||||
|
{"EISCONN", EISCONN},
|
||||||
|
{"ENOTCONN", ENOTCONN},
|
||||||
|
{"ESHUTDOWN", ESHUTDOWN},
|
||||||
|
{"ETOOMANYREFS", ETOOMANYREFS},
|
||||||
|
{"ETIMEDOUT", ETIMEDOUT},
|
||||||
|
{"ECONNREFUSED", ECONNREFUSED},
|
||||||
|
{"EHOSTDOWN", EHOSTDOWN},
|
||||||
|
{"EHOSTUNREACH", EHOSTUNREACH},
|
||||||
|
{"EALREADY", EALREADY},
|
||||||
|
{"EINPROGRESS", EINPROGRESS},
|
||||||
|
{"ESTALE", ESTALE},
|
||||||
|
{"EUCLEAN", EUCLEAN},
|
||||||
|
{"ENOTNAM", ENOTNAM},
|
||||||
|
{"ENAVAIL", ENAVAIL},
|
||||||
|
{"EISNAM", EISNAM},
|
||||||
|
{"EREMOTEIO", EREMOTEIO},
|
||||||
|
{"EDQUOT", EDQUOT},
|
||||||
|
{"ENOMEDIUM", ENOMEDIUM},
|
||||||
|
{"EMEDIUMTYPE", EMEDIUMTYPE},
|
||||||
|
{"ECANCELED", ECANCELED},
|
||||||
|
{"ENOKEY", ENOKEY},
|
||||||
|
{"EKEYEXPIRED", EKEYEXPIRED},
|
||||||
|
{"EKEYREVOKED", EKEYREVOKED},
|
||||||
|
{"EKEYREJECTED", EKEYREJECTED},
|
||||||
|
{"EOWNERDEAD", EOWNERDEAD},
|
||||||
|
{"ENOTRECOVERABLE", ENOTRECOVERABLE},
|
||||||
|
{"ERFKILL", ERFKILL},
|
||||||
|
{"EHWPOISON", EHWPOISON},
|
||||||
|
});
|
||||||
|
|
||||||
|
std::string ErrnoToName(int n) {
|
||||||
|
int err = n;
|
||||||
|
if (err < 0) {
|
||||||
|
err = -err;
|
||||||
|
}
|
||||||
|
auto str = std::string(s_errno_table.ToString(n));
|
||||||
|
if (str.empty()) {
|
||||||
|
str = std::to_string(n);
|
||||||
|
}
|
||||||
|
if (n < 0) {
|
||||||
|
return "-" + str;
|
||||||
|
} else {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int NameToErrno(const std::string_view& name) {
|
||||||
|
if (!name.empty() && name[0] == '-') {
|
||||||
|
return -(s_errno_table.ToInt(name.substr(1)));
|
||||||
|
} else {
|
||||||
|
return s_errno_table.ToInt(name);
|
||||||
|
}
|
||||||
|
}
|
49
UserDB.cpp
49
UserDB.cpp
|
@ -204,8 +204,9 @@ void UserDB::update_task()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_file(const std::string& path, std::unordered_map<int, std::string>& db)
|
std::vector<std::pair<int, std::string>> parse_file(const std::string& path)
|
||||||
{
|
{
|
||||||
|
std::vector<std::pair<int, std::string>> entries;
|
||||||
std::ifstream fs(path);
|
std::ifstream fs(path);
|
||||||
|
|
||||||
int line_num = 1;
|
int line_num = 1;
|
||||||
|
@ -232,11 +233,9 @@ void parse_file(const std::string& path, std::unordered_map<int, std::string>& d
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Just in case there are multiple entries, only the first id->name is used
|
entries.emplace_back(id, name);
|
||||||
if (db.count(id) == 0) {
|
|
||||||
db.emplace(std::make_pair(id, name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserDB::update()
|
void UserDB::update()
|
||||||
|
@ -245,8 +244,18 @@ void UserDB::update()
|
||||||
std::unordered_map<int, std::string> groups;
|
std::unordered_map<int, std::string> groups;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parse_file(_dir + "/passwd", users);
|
for (auto& e : parse_file(_dir + "/passwd")) {
|
||||||
parse_file(_dir + "/group", groups);
|
// Just in case there are multiple entries, only the first id->name is used
|
||||||
|
if (users.count(e.first) == 0) {
|
||||||
|
users.emplace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& e : parse_file(_dir + "/group")) {
|
||||||
|
// Just in case there are multiple entries, only the first id->name is used
|
||||||
|
if (groups.count(e.first) == 0) {
|
||||||
|
groups.emplace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
Logger::Warn("UserDB: Update failed: %s", ex.what());
|
Logger::Warn("UserDB: Update failed: %s", ex.what());
|
||||||
return;
|
return;
|
||||||
|
@ -256,3 +265,29 @@ void UserDB::update()
|
||||||
_users = users;
|
_users = users;
|
||||||
_groups = groups;
|
_groups = groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int UserDB::UserNameToUid(const std::string& name) {
|
||||||
|
try {
|
||||||
|
for (auto& e : parse_file("/etc/passwd")) {
|
||||||
|
if (e.second == name) {
|
||||||
|
return e.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UserDB::GroupNameToGid(const std::string& name) {
|
||||||
|
try {
|
||||||
|
for (auto& e : parse_file("/etc/group")) {
|
||||||
|
if (e.second == name) {
|
||||||
|
return e.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
3
UserDB.h
3
UserDB.h
|
@ -37,6 +37,9 @@ public:
|
||||||
|
|
||||||
void update(); // Exposed only to simplify tests
|
void update(); // Exposed only to simplify tests
|
||||||
|
|
||||||
|
static int UserNameToUid(const std::string& name);
|
||||||
|
static int GroupNameToGid(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void inotify_task();
|
void inotify_task();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@
|
||||||
AUOMS_BUILDVERSION_MAJOR=2
|
AUOMS_BUILDVERSION_MAJOR=2
|
||||||
AUOMS_BUILDVERSION_MINOR=0
|
AUOMS_BUILDVERSION_MINOR=0
|
||||||
AUOMS_BUILDVERSION_PATCH=0
|
AUOMS_BUILDVERSION_PATCH=0
|
||||||
AUOMS_BUILDVERSION_BUILDNR=10
|
AUOMS_BUILDVERSION_BUILDNR=12
|
||||||
AUOMS_BUILDVERSION_DATE=20190421
|
AUOMS_BUILDVERSION_DATE=20190501
|
||||||
AUOMS_BUILDVERSION_STATUS=Developer_Build
|
AUOMS_BUILDVERSION_STATUS=Developer_Build
|
||||||
|
|
71
auomsctl.cpp
71
auomsctl.cpp
|
@ -77,9 +77,6 @@ int show_audit_status() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Netlink netlink;
|
Netlink netlink;
|
||||||
netlink.SetQuite();
|
netlink.SetQuite();
|
||||||
|
|
||||||
|
@ -116,9 +113,6 @@ int list_rules(bool raw_fmt, const std::string& key) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Netlink netlink;
|
Netlink netlink;
|
||||||
netlink.SetQuite();
|
netlink.SetQuite();
|
||||||
|
|
||||||
|
@ -163,9 +157,6 @@ int delete_rules(const std::string& key) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Netlink netlink;
|
Netlink netlink;
|
||||||
netlink.SetQuite();
|
netlink.SetQuite();
|
||||||
|
|
||||||
|
@ -222,10 +213,7 @@ int load_rules(const std::string& path) {
|
||||||
int exit_code = 0;
|
int exit_code = 0;
|
||||||
try {
|
try {
|
||||||
auto lines = ReadFile(path);
|
auto lines = ReadFile(path);
|
||||||
auto rules = ParseRules(lines);
|
auto rules = ParseRules(lines, nullptr);
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Netlink netlink;
|
Netlink netlink;
|
||||||
netlink.SetQuite();
|
netlink.SetQuite();
|
||||||
|
@ -268,9 +256,16 @@ int load_rules(const std::string& path) {
|
||||||
int print_rules(const std::string& path) {
|
int print_rules(const std::string& path) {
|
||||||
try {
|
try {
|
||||||
auto lines = ReadFile(path);
|
auto lines = ReadFile(path);
|
||||||
auto rules = ParseRules(lines);
|
std::vector<AuditRule> rules;
|
||||||
for (auto& rule: rules) {
|
for (int i = 0; i < lines.size(); ++i) {
|
||||||
std::cout << rule.CanonicalText() << std::endl;
|
AuditRule rule;
|
||||||
|
std::string error;
|
||||||
|
if (rule.Parse(lines[i], error)) {
|
||||||
|
std::cout << rule.CanonicalText() << std::endl;
|
||||||
|
} else if (!error.empty()) {
|
||||||
|
std::cout << "Failed to parse line " << i+1 << ": " << error << std::endl;
|
||||||
|
std::cout << " " << lines[i] << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (std::exception& ex) {
|
} catch (std::exception& ex) {
|
||||||
std::cerr << ex.what() << std::endl;
|
std::cerr << ex.what() << std::endl;
|
||||||
|
@ -282,8 +277,8 @@ int print_rules(const std::string& path) {
|
||||||
|
|
||||||
int merge_rules(const std::string& file1, const std::string& file2) {
|
int merge_rules(const std::string& file1, const std::string& file2) {
|
||||||
try {
|
try {
|
||||||
auto rules1 = ParseRules(ReadFile(file1));
|
auto rules1 = ParseRules(ReadFile(file1), nullptr);
|
||||||
auto rules2 = ParseRules(ReadFile(file2));
|
auto rules2 = ParseRules(ReadFile(file2), nullptr);
|
||||||
auto merged_rules = MergeRules(rules1, rules2);
|
auto merged_rules = MergeRules(rules1, rules2);
|
||||||
for (auto& rule: merged_rules) {
|
for (auto& rule: merged_rules) {
|
||||||
std::cout << rule.CanonicalText() << std::endl;
|
std::cout << rule.CanonicalText() << std::endl;
|
||||||
|
@ -298,8 +293,8 @@ int merge_rules(const std::string& file1, const std::string& file2) {
|
||||||
|
|
||||||
int diff_rules(const std::string& file1, const std::string& file2) {
|
int diff_rules(const std::string& file1, const std::string& file2) {
|
||||||
try {
|
try {
|
||||||
auto rules1 = MergeRules(ParseRules(ReadFile(file1)));
|
auto rules1 = MergeRules(ParseRules(ReadFile(file1), nullptr));
|
||||||
auto rules2 = MergeRules(ParseRules(ReadFile(file2)));
|
auto rules2 = MergeRules(ParseRules(ReadFile(file2), nullptr));
|
||||||
auto diffed_rules = DiffRules(rules1, rules2, "");
|
auto diffed_rules = DiffRules(rules1, rules2, "");
|
||||||
for (auto& rule: diffed_rules) {
|
for (auto& rule: diffed_rules) {
|
||||||
std::cout << rule.CanonicalText() << std::endl;
|
std::cout << rule.CanonicalText() << std::endl;
|
||||||
|
@ -318,9 +313,6 @@ int show_auoms_status() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
UnixDomainWriter io("/var/run/auoms/status.socket");
|
UnixDomainWriter io("/var/run/auoms/status.socket");
|
||||||
if (!io.Open()) {
|
if (!io.Open()) {
|
||||||
std::cout << "auoms is not running" << std::endl;
|
std::cout << "auoms is not running" << std::endl;
|
||||||
|
@ -676,10 +668,6 @@ int enable_auoms() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
Signals::SetExitHandler([](){ exit(1); });
|
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
// 0 on success
|
// 0 on success
|
||||||
// 1 if service could not be enabled
|
// 1 if service could not be enabled
|
||||||
|
@ -739,10 +727,6 @@ int disable_auoms() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
Signals::SetExitHandler([](){ exit(1); });
|
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
// 0 on success
|
// 0 on success
|
||||||
// 1 if service could not be disabled
|
// 1 if service could not be disabled
|
||||||
|
@ -884,9 +868,6 @@ int tap_audit() {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Logger::Info("Connecting to AUDIT NETLINK socket");
|
Logger::Info("Connecting to AUDIT NETLINK socket");
|
||||||
auto ret = netlink.Open(handler);
|
auto ret = netlink.Open(handler);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
|
@ -1068,9 +1049,6 @@ int monitor_auoms_events() {
|
||||||
std::string sock_path = "/var/run/auoms/auomsctl.socket";
|
std::string sock_path = "/var/run/auoms/auomsctl.socket";
|
||||||
std::string config_path = "/etc/opt/microsoft/auoms/outconf.d/auomsctl.conf";
|
std::string config_path = "/etc/opt/microsoft/auoms/outconf.d/auomsctl.conf";
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
UnixDomainListener listener(sock_path, 0666);
|
UnixDomainListener listener(sock_path, 0666);
|
||||||
if (!listener.Open()) {
|
if (!listener.Open()) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1106,7 +1084,7 @@ int monitor_auoms_events() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_rules() {
|
int set_rules() {
|
||||||
auto rules = ReadAuditRulesFromDir("/etc/opt/microsoft/auoms/rules.d");
|
auto rules = ReadAuditRulesFromDir("/etc/opt/microsoft/auoms/rules.d", nullptr);
|
||||||
std::vector<AuditRule> desired_rules;
|
std::vector<AuditRule> desired_rules;
|
||||||
for (auto& rule: rules) {
|
for (auto& rule: rules) {
|
||||||
// Only include the rule in the desired rules if it is supported on the host system
|
// Only include the rule in the desired rules if it is supported on the host system
|
||||||
|
@ -1117,14 +1095,14 @@ int set_rules() {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto rules = ReadActualAuditdRules(false);
|
auto rules = ReadActualAuditdRules(false, nullptr);
|
||||||
auto diff = DiffRules(rules, desired_rules, "");
|
auto diff = DiffRules(rules, desired_rules, "");
|
||||||
if (diff.empty()) {
|
if (diff.empty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Logger::Info("AuditRulesMonitor: Found desired audit rules not currently present in auditd rules files(s), adding new rules");
|
Logger::Info("AuditRulesMonitor: Found desired audit rules not currently present in auditd rules files(s), adding new rules");
|
||||||
// Re-read rules but exclude auoms rules
|
// Re-read rules but exclude auoms rules
|
||||||
rules = ReadActualAuditdRules(true);
|
rules = ReadActualAuditdRules(true, nullptr);
|
||||||
// Re-calculate diff
|
// Re-calculate diff
|
||||||
diff = DiffRules(rules, desired_rules, "");
|
diff = DiffRules(rules, desired_rules, "");
|
||||||
if (WriteAuditdRules(diff)) {
|
if (WriteAuditdRules(diff)) {
|
||||||
|
@ -1156,7 +1134,7 @@ bool is_set_intersect(T a, T b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_rules() {
|
int load_rules() {
|
||||||
auto rules = ReadAuditRulesFromDir("/etc/opt/microsoft/auoms/rules.d");
|
auto rules = ReadAuditRulesFromDir("/etc/opt/microsoft/auoms/rules.d", nullptr);
|
||||||
std::vector<AuditRule> desired_rules;
|
std::vector<AuditRule> desired_rules;
|
||||||
for (auto& rule: rules) {
|
for (auto& rule: rules) {
|
||||||
// Only include the rule in the desired rules if it is supported on the host system
|
// Only include the rule in the desired rules if it is supported on the host system
|
||||||
|
@ -1168,9 +1146,6 @@ int load_rules() {
|
||||||
|
|
||||||
Netlink netlink;
|
Netlink netlink;
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
|
|
||||||
Logger::Info("Connecting to AUDIT NETLINK socket");
|
Logger::Info("Connecting to AUDIT NETLINK socket");
|
||||||
auto ret = netlink.Open(nullptr);
|
auto ret = netlink.Open(nullptr);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
|
@ -1285,10 +1260,6 @@ int upgrade() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Signals::Init();
|
|
||||||
Signals::Start();
|
|
||||||
Signals::SetExitHandler([](){ exit(1); });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use auditd plugin file to determine if auoms should be enabled
|
// Use auditd plugin file to determine if auoms should be enabled
|
||||||
if (is_auditd_plugin_enabled()) {
|
if (is_auditd_plugin_enabled()) {
|
||||||
|
@ -1354,6 +1325,10 @@ int main(int argc, char**argv) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Signals::Init();
|
||||||
|
Signals::Start();
|
||||||
|
Signals::SetExitHandler([](){ exit(1); });
|
||||||
|
|
||||||
if (strcmp(argv[1], "-v") == 0) {
|
if (strcmp(argv[1], "-v") == 0) {
|
||||||
std::cout << std::string(AUOMS_VERSION) << std::endl;
|
std::cout << std::string(AUOMS_VERSION) << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
# Default is ${run_dir}/input.socket
|
# Default is ${run_dir}/input.socket
|
||||||
#socket_path = /var/run/auoms/input.socket
|
#socket_path = /var/run/auoms/input.socket
|
||||||
|
|
||||||
# The path to the file where auomscollect will keep trask of which events have been sent to auoms
|
# The path to the file where auomscollect will keep track of which events have been sent to auoms
|
||||||
#
|
#
|
||||||
# Default is ${data_dir}/collect.cursor
|
# Default is ${data_dir}/collect.cursor
|
||||||
#cursor_path = /var/opt/microsoft/auoms/data/collect.cursor
|
#cursor_path = /var/opt/microsoft/auoms/data/collect.cursor
|
||||||
|
|
|
@ -28,7 +28,6 @@ if [ "$1" = "upgrade" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
%Postinstall_100
|
%Postinstall_100
|
||||||
echo "Postinstall_100 $1"
|
|
||||||
if [ "$1" = "configure" ]; then
|
if [ "$1" = "configure" ]; then
|
||||||
if [ -e ${{AUOMS_AUDISP_CONF}}.auomssave ]; then
|
if [ -e ${{AUOMS_AUDISP_CONF}}.auomssave ]; then
|
||||||
if [ -e ${{AUOMS_AUDISP_CONF}} ]; then
|
if [ -e ${{AUOMS_AUDISP_CONF}} ]; then
|
||||||
|
|
Загрузка…
Ссылка в новой задаче