/* * auditd-plugin-clickhouse is an auditd plugin for sending auditd data * to clickhouse DB. * Copyright (C) 2019 Aleksei Nikiforov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "auditd-record.hpp" #include #include #include #define register_record_type(audit_type, record_type) \ static const AbstractRecordFieldFactory::AuditRecordFieldRegister record_register_##audit_type(audit_type) register_record_type(AUPARSE_TYPE_UNCLASSIFIED, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_UID, IntegerRecordField); register_record_type(AUPARSE_TYPE_GID, IntegerRecordField); register_record_type(AUPARSE_TYPE_SYSCALL, IntegerRecordField); register_record_type(AUPARSE_TYPE_ARCH, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_EXIT, IntegerRecordField); register_record_type(AUPARSE_TYPE_ESCAPED, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_PERM, IntegerRecordField); register_record_type(AUPARSE_TYPE_MODE, IntegerRecordField); register_record_type(AUPARSE_TYPE_SOCKADDR, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_FLAGS, IntegerRecordField); register_record_type(AUPARSE_TYPE_PROMISC, IntegerRecordField); register_record_type(AUPARSE_TYPE_CAPABILITY, IntegerRecordField); register_record_type(AUPARSE_TYPE_SUCCESS, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_A0, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_A1, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_A2, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_A3, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_SIGNAL, IntegerRecordField); register_record_type(AUPARSE_TYPE_LIST, IntegerRecordField); register_record_type(AUPARSE_TYPE_TTY_DATA, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_SESSION, IntegerRecordField); register_record_type(AUPARSE_TYPE_CAP_BITMAP, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_NFPROTO, IntegerRecordField); register_record_type(AUPARSE_TYPE_ICMPTYPE, IntegerRecordField); register_record_type(AUPARSE_TYPE_PROTOCOL, IntegerRecordField); register_record_type(AUPARSE_TYPE_ADDR, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_PERSONALITY, IntegerRecordField); register_record_type(AUPARSE_TYPE_SECCOMP, IntegerRecordField); register_record_type(AUPARSE_TYPE_OFLAG, IntegerRecordField); register_record_type(AUPARSE_TYPE_MMAP, IntegerRecordField); register_record_type(AUPARSE_TYPE_MODE_SHORT, IntegerRecordField); register_record_type(AUPARSE_TYPE_MAC_LABEL, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_PROCTITLE, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_HOOK, IntegerRecordField); register_record_type(AUPARSE_TYPE_NETACTION, IntegerRecordField); register_record_type(AUPARSE_TYPE_MACPROTO, IntegerRecordField); register_record_type(AUPARSE_TYPE_IOCTL_REQ, IntegerRecordField); register_record_type(AUPARSE_TYPE_ESCAPED_KEY, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_ESCAPED_FILE, InterpretedStringRecordField); register_record_type(AUPARSE_TYPE_FANOTIFY, InterpretedStringRecordField); #undef register_record_type AbstractRecordFieldFactory& AbstractRecordFieldFactory::instance() { static AbstractRecordFieldFactory instance; return instance; } std::shared_ptr AbstractRecordFieldFactory::createFromAuditRecord(const std::string &name, auparse_state_t *record) { AbstractRecordFieldFactory &inst = instance(); auparse_type_t record_type = static_cast(auparse_get_field_type(record)); auto record_type_factory = inst.m_factoryMap.find(record_type); if ((record_type_factory != inst.m_factoryMap.end()) && (record_type_factory->second)) { return record_type_factory->second(name, record); } else { // fallback return InterpretedStringRecordField::createRecord(name, record); } } AbstractRecordField::AbstractRecordField(const std::string &name) : m_name(name) { } std::shared_ptr IntegerRecordField::createRecord(const std::string &name, auparse_state_t *record) { std::shared_ptr result; result.reset(new IntegerRecordField(name, record)); return result; } IntegerRecordField::IntegerRecordField(const std::string &name, auparse_state_t *record) : AbstractRecordField(name) { if (record) { m_value = auparse_get_field_int(record); } } void IntegerRecordField::addToColumn(clickhouse::ColumnRef column) const { auto nullable = column->As(); if (!nullable) { throw std::runtime_error("Invalid column type: not ColumnNullable"); } auto nested = nullable->Nested(); if ((!nested) || (nested->Type()->GetCode() != clickhouse::Type::Int64)) { throw std::runtime_error("Invalid nested column type: not Int64"); } auto data_column = std::make_shared(); auto null_column = std::make_shared(); if (m_value) { data_column->Append(*m_value); null_column->Append(0); } else { data_column->Append(0); null_column->Append(1); } column->Append(std::make_shared(data_column, null_column)); } AbstractRecordField::Type IntegerRecordField::getType() const { return AbstractRecordField::Type::Int; } CommonStringRecordField::CommonStringRecordField(const std::string &name) : AbstractRecordField(name) { } void CommonStringRecordField::addToColumn(clickhouse::ColumnRef column) const { auto nullable = column->As(); if (!nullable) { throw std::runtime_error("Invalid column type: not ColumnNullable"); } auto nested = nullable->Nested(); if ((!nested) || (nested->Type()->GetCode() != clickhouse::Type::String)) { throw std::runtime_error("Invalid nested column type: not String"); } auto data_column = std::make_shared(); auto null_column = std::make_shared(); if (m_value) { data_column->Append(*m_value); null_column->Append(0); } else { data_column->Append(std::string()); null_column->Append(1); } column->Append(std::make_shared(data_column, null_column)); } std::shared_ptr StringRecordField::createRecord(const std::string &name, auparse_state_t *record) { std::shared_ptr result; result.reset(new StringRecordField(name, record)); return result; } StringRecordField::StringRecordField(const std::string &name, auparse_state_t *record) : CommonStringRecordField(name) { if (record) { m_value = auparse_get_field_str(record); } } AbstractRecordField::Type StringRecordField::getType() const { return AbstractRecordField::Type::String; } std::shared_ptr InterpretedStringRecordField::createRecord(const std::string &name, auparse_state_t *record) { std::shared_ptr result; result.reset(new InterpretedStringRecordField(name, record)); return result; } InterpretedStringRecordField::InterpretedStringRecordField(const std::string &name, auparse_state_t *record) : CommonStringRecordField(name) { if (record) { m_value = auparse_interpret_field(record); } } AbstractRecordField::Type InterpretedStringRecordField::getType() const { return AbstractRecordField::Type::InterpretedString; }