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-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>
# define register_record_type(audit_type, record_type) \
static const AbstractRecordFieldFactory : : AuditRecordFieldRegister < record_type > 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 ;
}
2019-12-11 17:16:28 +03:00
std : : shared_ptr < AbstractRecordField > AbstractRecordFieldFactory : : createFromAuditRecord ( const std : : string & field_name , auparse_type_t field_type )
2019-12-09 11:44:51 +03:00
{
AbstractRecordFieldFactory & inst = instance ( ) ;
2019-12-11 17:16:28 +03:00
auto record_type_factory = inst . m_factoryMap . find ( field_type ) ;
2019-12-09 11:44:51 +03:00
if ( ( record_type_factory ! = inst . m_factoryMap . end ( ) ) & & ( record_type_factory - > second ) )
{
2019-12-11 17:16:28 +03:00
return record_type_factory - > second ( field_name ) ;
2019-12-09 11:44:51 +03:00
}
else
{
2019-12-11 16:35:42 +03:00
// fallback to string
2019-12-11 17:16:28 +03:00
fprintf ( stderr , " Warning: unknown record type for record name \" %s \" \n " , field_name . c_str ( ) ) ;
return InterpretedStringRecordField : : createRecord ( field_name ) ;
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 ;
}