2019-12-09 11:44:51 +03:00
/*
* auditd - plugin - clickhouse is an auditd plugin for sending auditd data
* to clickhouse DB .
* Copyright ( C ) 2019 Aleksei Nikiforov < darktemplar @ basealt . ru >
*
* 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 < https : //www.gnu.org/licenses/>.
*
*/
# include "auditd-record.hpp"
2019-12-12 15:01:59 +03:00
# include <functional>
# include <set>
2019-12-11 17:16:28 +03:00
# include <clickhouse-cpp/columns/array.h>
2019-12-09 11:44:51 +03:00
# include <clickhouse-cpp/columns/nullable.h>
# include <clickhouse-cpp/columns/numeric.h>
# include <clickhouse-cpp/columns/string.h>
2019-12-12 15:01:59 +03:00
namespace {
2019-12-09 11:44:51 +03:00
2019-12-12 15:01:59 +03:00
std : : map < auparse_type_t , std : : function < bool ( const std : : string & ) > > & get_audit_type_check_instance ( )
2019-12-09 11:44:51 +03:00
{
2019-12-12 15:01:59 +03:00
static std : : map < auparse_type_t , std : : function < bool ( const std : : string & ) > > instance ;
2019-12-09 11:44:51 +03:00
return instance ;
}
2019-12-12 15:01:59 +03:00
class AuditTypeCheckRegister
{
public :
AuditTypeCheckRegister ( auparse_type_t type , const std : : function < bool ( const std : : string & ) > & func )
{
get_audit_type_check_instance ( ) [ type ] = func ;
}
} ;
std : : function < bool ( const std : : string & ) > integer_record_type_check_function ( )
{
return [ ] ( const std : : string & value ) - > bool {
std : : set < std : : string > allowed_values = {
" integer "
} ;
return ( allowed_values . find ( value ) ! = allowed_values . end ( ) ) ;
} ;
}
std : : function < bool ( const std : : string & ) > interpreted_string_record_type_check_function ( )
{
return [ ] ( const std : : string & value ) - > bool {
std : : set < std : : string > allowed_values = {
" string " ,
" string_array "
} ;
return ( allowed_values . find ( value ) ! = allowed_values . end ( ) ) ;
} ;
}
} // unnamed namespace
# define register_record_type(audit_type, check_function) \
static const AuditTypeCheckRegister audit_type_check_register_ # # audit_type ( audit_type , check_function )
register_record_type ( AUPARSE_TYPE_UNCLASSIFIED , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_UID , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_GID , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SYSCALL , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ARCH , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_EXIT , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ESCAPED , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_PERM , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_MODE , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SOCKADDR , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_FLAGS , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_PROMISC , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_CAPABILITY , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SUCCESS , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_A0 , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_A1 , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_A2 , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_A3 , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SIGNAL , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_LIST , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_TTY_DATA , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SESSION , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_CAP_BITMAP , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_NFPROTO , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ICMPTYPE , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_PROTOCOL , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ADDR , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_PERSONALITY , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_SECCOMP , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_OFLAG , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_MMAP , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_MODE_SHORT , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_MAC_LABEL , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_PROCTITLE , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_HOOK , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_NETACTION , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_MACPROTO , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_IOCTL_REQ , integer_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ESCAPED_KEY , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_ESCAPED_FILE , interpreted_string_record_type_check_function ( ) ) ;
register_record_type ( AUPARSE_TYPE_FANOTIFY , interpreted_string_record_type_check_function ( ) ) ;
# undef register_record_type
bool check_field_type ( auparse_type_t field_type , const std : : string & database_type , const std : : string & database_field_name )
2019-12-09 11:44:51 +03:00
{
2019-12-12 15:01:59 +03:00
const auto & check_instance = get_audit_type_check_instance ( ) ;
2019-12-09 11:44:51 +03:00
2019-12-12 15:01:59 +03:00
auto check_type_function = check_instance . find ( field_type ) ;
if ( check_type_function ! = check_instance . end ( ) )
2019-12-09 11:44:51 +03:00
{
2019-12-12 15:01:59 +03:00
return check_type_function - > second ( database_type ) ;
2019-12-09 11:44:51 +03:00
}
else
{
2019-12-12 15:01:59 +03:00
fprintf ( stderr , " Warning: unknown record type for record name \" %s \" \n " , database_field_name . c_str ( ) ) ;
return interpreted_string_record_type_check_function ( ) ( database_type ) ;
2019-12-09 11:44:51 +03:00
}
}
AbstractRecordField : : AbstractRecordField ( const std : : string & name )
: m_name ( name )
{
}
2019-12-09 12:19:58 +03:00
CommonStringRecordField : : CommonStringRecordField ( const std : : string & name )
2019-12-09 11:44:51 +03:00
: AbstractRecordField ( name )
{
}
2019-12-09 12:19:58 +03:00
void CommonStringRecordField : : addToColumn ( const std : : vector < clickhouse : : ColumnRef > & columns ) const
2019-12-09 11:44:51 +03:00
{
2019-12-09 12:19:58 +03:00
if ( ( columns . size ( ) ! = 1 ) | | ( ! columns [ 0 ] ) )
2019-12-09 11:44:51 +03:00
{
2019-12-09 12:19:58 +03:00
throw std : : runtime_error ( " CommonStringRecordField::addToColumn: invalid columns argument " ) ;
2019-12-09 11:44:51 +03:00
}
2019-12-09 12:19:58 +03:00
auto nullable = columns [ 0 ] - > As < clickhouse : : ColumnNullable > ( ) ;
2019-12-09 11:44:51 +03:00
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 < clickhouse : : ColumnString > ( ) ;
auto null_column = std : : make_shared < clickhouse : : ColumnUInt8 > ( ) ;
if ( m_value )
{
data_column - > Append ( * m_value ) ;
null_column - > Append ( 0 ) ;
}
else
{
data_column - > Append ( std : : string ( ) ) ;
null_column - > Append ( 1 ) ;
}
2019-12-09 12:19:58 +03:00
columns [ 0 ] - > Append ( std : : make_shared < clickhouse : : ColumnNullable > ( data_column , null_column ) ) ;
2019-12-09 11:44:51 +03:00
}
2019-12-11 17:16:28 +03:00
std : : shared_ptr < AbstractRecordField > StringRecordField : : createRecord ( const std : : string & name )
2019-12-09 11:44:51 +03:00
{
std : : shared_ptr < AbstractRecordField > result ;
2019-12-11 17:16:28 +03:00
result . reset ( new StringRecordField ( name ) ) ;
2019-12-09 11:44:51 +03:00
return result ;
}
2019-12-11 17:16:28 +03:00
void StringRecordField : : addOrUpdateValue ( auparse_state_t * record )
2019-12-09 11:44:51 +03:00
{
if ( record )
{
m_value = auparse_get_field_str ( record ) ;
}
2019-12-11 17:16:28 +03:00
else
{
m_value = boost : : none ;
}
}
StringRecordField : : StringRecordField ( const std : : string & name )
: CommonStringRecordField ( name )
{
2019-12-09 11:44:51 +03:00
}
AbstractRecordField : : Type StringRecordField : : getType ( ) const
{
return AbstractRecordField : : Type : : String ;
}
2019-12-11 17:16:28 +03:00
std : : shared_ptr < AbstractRecordField > InterpretedStringRecordField : : createRecord ( const std : : string & name )
2019-12-09 11:44:51 +03:00
{
std : : shared_ptr < AbstractRecordField > result ;
2019-12-11 17:16:28 +03:00
result . reset ( new InterpretedStringRecordField ( name ) ) ;
2019-12-09 11:44:51 +03:00
return result ;
}
2019-12-11 17:16:28 +03:00
InterpretedStringRecordField : : InterpretedStringRecordField ( const std : : string & name )
2019-12-09 11:44:51 +03:00
: CommonStringRecordField ( name )
2019-12-11 17:16:28 +03:00
{
}
void InterpretedStringRecordField : : addOrUpdateValue ( auparse_state_t * record )
2019-12-09 11:44:51 +03:00
{
if ( record )
{
m_value = auparse_interpret_field ( record ) ;
}
2019-12-11 17:16:28 +03:00
else
{
m_value = boost : : none ;
}
2019-12-09 11:44:51 +03:00
}
AbstractRecordField : : Type InterpretedStringRecordField : : getType ( ) const
{
return AbstractRecordField : : Type : : InterpretedString ;
}
2019-12-09 12:19:58 +03:00
2019-12-11 17:16:28 +03:00
std : : shared_ptr < AbstractRecordField > IntegerRecordField : : createRecord ( const std : : string & name )
2019-12-09 12:19:58 +03:00
{
std : : shared_ptr < AbstractRecordField > result ;
2019-12-11 17:16:28 +03:00
result . reset ( new IntegerRecordField ( name ) ) ;
2019-12-09 12:19:58 +03:00
return result ;
}
2019-12-11 17:16:28 +03:00
IntegerRecordField : : IntegerRecordField ( const std : : string & name )
: InterpretedStringRecordField ( name )
{
}
void IntegerRecordField : : addOrUpdateValue ( auparse_state_t * record )
2019-12-09 12:19:58 +03:00
{
2019-12-11 17:16:28 +03:00
InterpretedStringRecordField : : addOrUpdateValue ( record ) ;
2019-12-09 12:19:58 +03:00
if ( record )
{
m_int_value = auparse_get_field_int ( record ) ;
}
2019-12-11 17:16:28 +03:00
else
{
m_int_value = boost : : none ;
}
2019-12-09 12:19:58 +03:00
}
void IntegerRecordField : : addToColumn ( const std : : vector < clickhouse : : ColumnRef > & columns ) const
{
if ( ( columns . size ( ) ! = 2 ) | | ( ! columns [ 0 ] ) | | ( ! columns [ 1 ] ) )
{
throw std : : runtime_error ( " IntegerRecordField::addToColumn: invalid columns argument " ) ;
}
auto nullable = columns [ 0 ] - > As < clickhouse : : ColumnNullable > ( ) ;
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 < clickhouse : : ColumnInt64 > ( ) ;
auto null_column = std : : make_shared < clickhouse : : ColumnUInt8 > ( ) ;
if ( m_int_value )
{
data_column - > Append ( * m_int_value ) ;
null_column - > Append ( 0 ) ;
}
else
{
data_column - > Append ( 0 ) ;
null_column - > Append ( 1 ) ;
}
std : : vector < clickhouse : : ColumnRef > string_columns ;
string_columns . push_back ( columns [ 1 ] ) ;
columns [ 0 ] - > Append ( std : : make_shared < clickhouse : : ColumnNullable > ( data_column , null_column ) ) ;
// now also add string value
InterpretedStringRecordField : : addToColumn ( string_columns ) ;
}
AbstractRecordField : : Type IntegerRecordField : : getType ( ) const
{
return AbstractRecordField : : Type : : Int ;
}
2019-12-11 17:16:28 +03:00
std : : shared_ptr < AbstractRecordField > InterpretedStringArrayRecordField : : createRecord ( const std : : string & name )
{
std : : shared_ptr < AbstractRecordField > result ;
result . reset ( new InterpretedStringArrayRecordField ( name ) ) ;
return result ;
}
void InterpretedStringArrayRecordField : : addOrUpdateValue ( auparse_state_t * record )
{
if ( record )
{
m_value . push_back ( auparse_interpret_field ( record ) ) ;
}
}
void InterpretedStringArrayRecordField : : addToColumn ( const std : : vector < clickhouse : : ColumnRef > & columns ) const
{
if ( ( columns . size ( ) ! = 1 ) | | ( ! columns [ 0 ] ) )
{
throw std : : runtime_error ( " InterpretedStringArrayRecordField::addToColumn: invalid columns argument " ) ;
}
auto array = columns [ 0 ] - > As < clickhouse : : ColumnArray > ( ) ;
if ( ! array )
{
throw std : : runtime_error ( " Invalid column type: not ColumnArray " ) ;
}
auto data_column = std : : make_shared < clickhouse : : ColumnString > ( ) ;
for ( auto iter = m_value . begin ( ) ; iter ! = m_value . end ( ) ; + + iter )
{
data_column - > Append ( * iter ) ;
}
array - > AppendAsColumn ( data_column ) ;
}
InterpretedStringArrayRecordField : : InterpretedStringArrayRecordField ( const std : : string & name )
: AbstractRecordField ( name )
{
}
AbstractRecordField : : Type InterpretedStringArrayRecordField : : getType ( ) const
{
return AbstractRecordField : : Type : : InterpretedStringArray ;
}