Failed to fetch fork details. Try again later.
-
alex authoreda346aff3
Forked from
Романов Никита Сергеевич / libakrypt-stb34
Source project has a limited visibility.
/* ----------------------------------------------------------------------------------------------- */
/* Copyright (c) 2024 by Axel Kenzo, axelkenzo@mail.ru */
/* */
/* Прикладной модуль, реализующий процедуры вычисления сохранения контрольных сумм */
/* */
/* aktool_icode_evaluate.c */
/* ----------------------------------------------------------------------------------------------- */
#include "aktool.h"
#include <libakrypt.h>
#ifdef AK_HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef AK_HAVE_GELF_H
#include <gelf.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#endif
#ifdef AK_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef AK_HAVE_DIRENT_H
#include <dirent.h>
#endif
/* ----------------------------------------------------------------------------------------------- */
/* Функция для создания и удаления ключевой информации */
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_create_handle( aktool_ki_t *ki )
{
ak_oid koid = NULL;
char oidstr[32];
/* начинаем с того, что проверяем, задан алгоритм хеширования или имитозащиты */
if( strlen( ki->key_file ) == 0 ) {
/* создаем алгоритм хеширования */
if(( ki->handle = ak_oid_new_object( ki->method )) == NULL ) {
aktool_error(_("wrong creation of internal context of %s algorithm"), ki->method->name[0]);
return ak_error_get_value();
}
/* устанавливаем указатели на обработчики */
ki->icode_file = ( ak_function_icode_file *) ak_hash_file;
ki->icode_file_offset = ( ak_function_icode_file_offset *) ak_hash_file_offset;
#ifdef AK_HAVE_GELF_H
ki->icode_ptr = ( ak_function_icode_ptr *) ak_hash_ptr;
ki->icode_clean = ( ak_function_clean *) ak_hash_clean;
ki->icode_update = ( ak_function_update *) ak_hash_update;
ki->icode_finalize = ( ak_function_finalize *) ak_hash_finalize;
#endif
ki->size = ak_hash_get_tag_size( ki->handle );
return ak_error_ok;
}
/* остальное посвящаем обработке алгоритмов имитозащиты */
ak_libakrypt_set_password_read_function( aktool_load_user_password );
if(( ki->handle = ak_skey_load_from_file( ki->key_file )) == NULL ) {
aktool_error(_("wrong reading a secret key from %s file"), ki->key_file );
return ak_error_get_value();
}
if(( koid = ((ak_skey)ki->handle)->oid ) == NULL ) {
ak_skey_delete( ki->handle );
aktool_error(_("null pointer to a secret key oid (%s file)"), ki->key_file );
return ak_error_null_pointer;
}
/* устанавливаем обработчики */
switch( koid->engine ) {
case hmac_function:
ki->icode_file = ( ak_function_icode_file *) ak_hmac_file;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
ki->icode_file_offset = ( ak_function_icode_file_offset *) ak_hmac_file_offset;
#ifdef AK_HAVE_GELF_H
ki->icode_ptr = ( ak_function_icode_ptr *) ak_hmac_ptr;
ki->icode_clean = ( ak_function_clean *) ak_hmac_clean;
ki->icode_update = ( ak_function_update *) ak_hmac_update;
ki->icode_finalize = ( ak_function_finalize *) ak_hmac_finalize;
#endif
ki->size = ak_hmac_get_tag_size( ki->handle );
ki->method = koid;
break;
case block_cipher:
/* сейчас поддерживается только имитовставка по ГОСТ Р 34.13-2015,
далее можно подумать о применении, например, aead режимов */
ak_snprintf( oidstr, sizeof( oidstr ), "cmac-%s", koid->name[0] );
if(( ki->method = ak_oid_find_by_name( oidstr )) == NULL ) {
aktool_error(_("unexpected block cipher identifier (%s)"), oidstr );
return ak_error_oid_name;
}
ki->icode_file = ( ak_function_icode_file *) ak_bckey_cmac_file;
ki->icode_file_offset = ( ak_function_icode_file_offset *) ak_bckey_cmac_file_offset;
#ifdef AK_HAVE_GELF_H
ki->icode_ptr = ( ak_function_icode_ptr *) ak_bckey_cmac;
ki->icode_clean = ( ak_function_clean *) ak_bckey_cmac_clean;
ki->icode_update = ( ak_function_update *) ak_bckey_cmac_update;
ki->icode_finalize = ( ak_function_finalize *) ak_bckey_cmac_finalize;
#endif
ki->size = ((ak_bckey)ki->handle)->bsize;
break;
default:
ak_skey_delete( ki->handle );
aktool_error(
_("using a secret key with unsupported type of authentication mechanism (%s)"),
koid->name[0] );
return ak_error_key_usage;
}
return ak_error_ok;
}
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_destroy_handle( aktool_ki_t *ki )
{
if( ki->method->engine == hash_function ) ak_oid_delete_object( ki->method, ki->handle );
else
ak_skey_delete( ki->handle );
return ak_error_ok;
}
/* ----------------------------------------------------------------------------------------------- */
/* функция выработки производного ключа */
/* ----------------------------------------------------------------------------------------------- */
ak_pointer aktool_icode_get_derived_key( const char *value, aktool_ki_t *ki, ak_uint64 fp_size )
{
struct file infp;
ak_pointer dkey = NULL;
size_t total_size = 0, blocks = 0;
/* проверяем надо ли делать производный ключ */
if(( ki->method->engine == hash_function ) || ( ki->key_derive == ak_false ))
return ki->handle;
else {
ak_oid koid = ((ak_skey)ki->handle)->oid;
dkey = ak_oid_new_object( koid );
/* имеем секретный ключ, надо сделать производный того же типа */
if(( ak_skey_set_derive_kdf_hmac_from_skey(
dkey,
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
kdf256, /* используем kdf256 */
ki->handle, /* исходный ключ */
(ak_uint8*) value, /* метка, в качестве которой выступает имя файла */
strlen( value ), /* длина метки */
NULL, 0 )) != ak_error_ok ) {
aktool_error(_("incorrect creation of derivative key (file %s)"), value );
if( dkey != NULL ) ak_oid_delete_object( koid, dkey );
return NULL;
}
if( koid->engine != block_cipher ) return dkey;
}
/* если снаружи ни чего не открыто, то делаем это самостоятельно */
if( fp_size != 0 ) total_size = fp_size;
else {
if( ak_file_open_to_read( &infp, value ) == ak_error_ok ) {
total_size = infp.size;
ak_file_close( &infp );
}
else return dkey;
}
/* в заключение, подправляем ресурс ключа алгоритма блочного шифрования
иначе придется вырабатывать следующий производный ключ и т.д. */
if(( blocks = ( total_size / ki->size )) > ((ak_skey)dkey)->resource.value.counter ) {
((ak_skey)dkey)->resource.value.counter = blocks;
if( ak_log_get_level() > ak_log_standard ) {
ak_error_message_fmt( ak_error_ok, __func__,
_("the resource of the derived key was increased up to %llu blocks (file %s)"),
(ak_uint64)((ak_skey)dkey)->resource.value.counter, value );
}
}
return dkey;
}
/* ----------------------------------------------------------------------------------------------- */
/* функции вычисления контрольных сумм */
/* ----------------------------------------------------------------------------------------------- */
#ifdef AK_HAVE_GELF_H
static int aktool_icode_evaluate_gelf( const char *value, aktool_ki_t *ki )
{
Elf *e;
size_t i, n;
GElf_Phdr phdr;
struct file fp;
ak_uint8 icode[256];
ak_uint8 *ptr = NULL;
ak_pointer dkey = NULL;
int error = ak_error_ok;
char segment_value[FILENAME_MAX];
if( ak_file_open_to_read( &fp, value ) != ak_error_ok ) return error;
if(( e = elf_begin( fp.fd, ELF_C_READ, NULL )) == NULL ) {
ak_file_close( &fp );
return ak_error_message_fmt( ak_error_access_file, __func__,
_("elf_begin() function failed: %s"), elf_errmsg(-1));
}
/* в случае выполнения данного условия файл является исполняемым */
if( elf_kind(e) != ELF_K_ELF ) goto labexit;
/* статистика */
ki->statistical_data.executables++;
/* определяем общее количество сегментов (программных заголовков) */
if( elf_getphdrnum(e, &n) != 0 ) {
error = ak_error_message_fmt( ak_error_access_file, __func__,
_("elf_getphdrnum() function failed: %s"), elf_errmsg(-1));
goto labexit;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
}
/* последовательно обрабатываем каждый сегмент */
for( i = 0; i < n; i++ ) {
if( gelf_getphdr( e, i, &phdr ) != &phdr ) {
error = ak_error_message_fmt( ak_error_access_file, __func__,
_("gelf_getphdr() function failed: %s"), elf_errmsg(-1));
goto labexit;
}
/* ищем только загружаемые сегменты */
if( phdr.p_type != PT_LOAD ) continue;
/* ищем только неисполняемые сегменты */
if( phdr.p_flags & PF_W ) continue;
/* обрабатываем найденный фрагмент */
if(( ptr = ak_file_mmap( &fp, NULL, phdr.p_filesz,
PROT_READ, MAP_PRIVATE, phdr.p_offset )) == NULL ) {
error = ak_error_message_fmt( ak_error_mmap_file, __func__, "mmap error" );
ki->statistical_data.skipped_executables++;
goto labexit;
}
/* формируем виртуальное имя файла - ключ доступа в виртуальной таблице */
ak_snprintf( segment_value, sizeof( segment_value ) -1, "%s/%08x", value,
(unsigned int) phdr.p_offset );
/* при необходимости, формируем производный ключ */
if(( dkey = aktool_icode_get_derived_key( segment_value, ki, fp.size )) == NULL ) {
ki->statistical_data.skipped_executables++;
error = ak_error_null_pointer;
goto labexit;
}
/* вычисляем контрольную сумму от заданного файла и помещаем ее в таблицу */
memset( icode, 0, sizeof( icode ));
((ak_uint64 *)icode)[0] = phdr.p_filesz;
error = ki->icode_ptr( dkey, ptr, phdr.p_filesz, icode +8, ki->size );
if( dkey != ki->handle ) ak_skey_delete( dkey );
/* проверка результата и его сохнение в хеш-таблице */
if( error == ak_error_ok ) {
if(( !ki->quiet ) && ( !ki->dont_show_icode))
aktool_icode_out( stdout, segment_value, ki, icode, ki->size +8 );
ak_htable_add_str_value( &ki->icodes, segment_value, icode, ki->size +8 );
}
else {
ki->statistical_data.skipped_executables++;
ak_file_unmap( &fp );
goto labexit;
}
ak_file_unmap( &fp );
} /* конец for */
labexit:
(void) elf_end( e );
ak_file_close( &fp );
return error;
}
#endif
/* ----------------------------------------------------------------------------------------------- */
static int aktool_icode_evaluate_function( const char *value, ak_pointer ptr )
{
ak_uint8 icode[256];
aktool_ki_t *ki = ptr;
ak_pointer dkey = NULL;
int error = ak_error_ok;
/* проверяем черный список */
if( ak_htable_get_str( &ki->exclude_file, value, NULL ) != NULL ) return ak_error_ok;
/* статистика */
ki->statistical_data.total_files++;
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
/* проверяем, что надо контролировать целостность всего файла */
if( !ki->only_segments ) {
/* вычисляем производный ключ */
if(( dkey = aktool_icode_get_derived_key( value, ki, 0 )) == NULL ) {
ki->statistical_data.skiped_files++;
return ak_error_null_pointer;
}
/* вычисляем контрольную сумму от заданного файла и помещаем ее в таблицу */
if(( ki->offset == 0 ) && ( ki->data_size = -1 ))
error = ki->icode_file( dkey, value, icode, ki->size );
else
error = ki->icode_file_offset( dkey, value, ki->offset, ki->data_size, icode, ki->size );
if( dkey != ki->handle ) ak_skey_delete( dkey );
/* проверка результата и его сохнение в хеш-таблице */
if( error == ak_error_ok ) {
ki->statistical_data.hashed_files++;
if(( !ki->quiet ) && ( !ki->dont_show_icode))
aktool_icode_out( stdout, value, ki, icode, ki->size );
ak_htable_add_str_value( &ki->icodes, value, icode, ki->size );
}
else {
ki->statistical_data.skiped_files++;
goto labexit;
}
} /* if(only_segments) */
/* теперь приступаем к разбору исполняемых файлов */
#ifdef AK_HAVE_GELF_H
if( !ki->ignore_segments ) error = aktool_icode_evaluate_gelf( value, ki );
#endif
labexit:
return error;
}
/* ----------------------------------------------------------------------------------------------- */
/*! \brief Функция вычисляет контрольные суммы по заданным спискам каталогов и файлов */
int aktool_icode_evaluate( aktool_ki_t *ki )
{
tchar *value = NULL;
int exit_status = EXIT_SUCCESS;
/* обнуляем счетчики */
memset( &ki->statistical_data, 0, sizeof( struct icode_stat ));
/* проверяем, что данные для обработки заданы пользователем */
if(( ki->include_file.count + ki->include_path.count ) == 0 ) {
aktool_error(_("the name of file or directory must be specified"));
return EXIT_FAILURE;
}
/* создаем контекст алгоритма хеширования или имитозащиты */
if( aktool_icode_create_handle( ki ) != ak_error_ok ) return EXIT_FAILURE;
/* начинаем с обхода файлов */
if( ki->include_file.count ) {
ak_list_first( &ki->include_file );
do{
aktool_icode_evaluate_function(( char * )ki->include_file.current->data, ki );
} while( ak_list_next( &ki->include_file ));
}
/* теперь продолжаем обходом каталогов */
if( ki->include_path.count ) {
ak_list_first( &ki->include_path );
do{
value = ( char * )ki->include_path.current->data;
/* проверяем черный список */
if( ak_htable_get_str( &ki->exclude_path, value, NULL ) != NULL ) continue;
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
/* запускаем вычисление контрольной суммы */
ak_file_find( value, ki->pattern, aktool_icode_evaluate_function, ki, ki->tree );
} while( ak_list_next( &ki->include_path ));
}
/* финальное сообщение об ошибках */
if( ki->statistical_data.skiped_files ) {
exit_status = EXIT_FAILURE;
aktool_error(_("aktool found %d error(s), try aktool with \"--audit-file stderr --audit 2\""
" options or see syslog messages"), ki->statistical_data.skiped_files );
}
/* вывод статистики */
if( !ki->quiet ) {
if(( !ki->dont_show_icode ) && ( !ki->dont_show_stat )) printf("\n");
if( !ki->dont_show_stat ) {
printf(_("the total number of files found: %llu, of which:\n"),
(long long unsigned int) ki->statistical_data.total_files );
printf(_(" %6llu have been discarded\n"),
(long long unsigned int) ki->statistical_data.skiped_files );
printf(_(" %6llu have been proceed\n"),
(long long unsigned int) ki->statistical_data.hashed_files );
#ifdef AK_HAVE_GELF_H
if( !ki->ignore_segments ) {
printf(_(" %6llu contain downloadable segments\n"),
(long long unsigned int) ki->statistical_data.executables );
if( ki->statistical_data.skipped_executables )
printf(_(" %6llu downloadable segments discarded\n"),
(long long unsigned int) ki->statistical_data.skipped_executables );
}
#endif
}
}
aktool_icode_destroy_handle( ki );
return exit_status;
}
/* ----------------------------------------------------------------------------------------------- */
/* функции проверки контрольных сумм */
/* ----------------------------------------------------------------------------------------------- */
static int aktool_icode_check_function( const char *value, ak_pointer ptr )
{
ak_uint8 icode[256];
ak_pointer dkey = NULL;
ak_uint8 *iptr = (ak_uint8 *)ptr;
int error = ak_error_ok;
/* статистика */
ki.statistical_data.total_files++;
/* вычисляем производный ключ */
if(( dkey = aktool_icode_get_derived_key( value, &ki, 0 )) == NULL ) {
ki.statistical_data.skiped_files++;
return ak_error_get_value();
}
/* вычисляем контрольную сумму от заданного файла и помещаем ее в таблицу */
error = ki.icode_file( dkey, value, icode, ki.size );
if( dkey != ki.handle ) ak_skey_delete( dkey );
if( error != ak_error_ok ) {
ak_error_message_fmt( error, __func__, _("%s is lost"), value );
if( !ki.quiet ) aktool_error(_("%s is lost"), value );
ki.statistical_data.skiped_files++;
ki.statistical_data.deleted_files++;
return error;
}
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
/* сравниваем значения */
if( memcmp( icode, iptr, ki.size ) != 0 ) {
ak_error_message_fmt( ak_error_not_equal_data, __func__, _("%s has been modified"), value );
if( !ki.quiet ) aktool_error(_("%s has been modified"), value );
ki.statistical_data.skiped_files++;
ki.statistical_data.changed_files++;
return ak_error_not_equal_data;
}
else ki.statistical_data.hashed_files++;
/* пытемся вывести результат в консоль */
if(( !ki.quiet ) && ( !ki.dont_show_icode )) {
printf("%s %s Ok\n", value, ak_ptr_to_hexstr( iptr, ki.size, ak_false ));
}
return ak_error_ok;
}
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_check_from_database( aktool_ki_t *ki )
{
size_t i = 0;
int exit_status = EXIT_FAILURE;
/* аудит */
if( ak_log_get_level() > ak_log_standard )
ak_error_message_fmt( ak_error_ok, __func__,
_("checking all files from given database: %s"), ki->pubkey_file );
/* основной цикл */
for( i = 0; i < ki->icodes.count; i++ ) {
ak_list list = &ki->icodes.list[i];
if( list->count == 0 ) continue;
ak_list_first( list );
do{
ak_keypair kp = (ak_keypair)list->current->data;
/* проверки */
if( kp->data == NULL ) {
ak_error_message( ak_error_null_pointer, __func__, _("using null pointer to keypair"));
return EXIT_FAILURE;
}
/* проверяем соотвествие длин */
if( ki->size != kp->value_length ) {
if( ki->size +8 == kp->value_length ) continue;
else {
/* расхождение в длинах имитовставок */
ki->statistical_data.total_files++;
ki->statistical_data.skiped_files++;
ak_error_message_fmt( ak_error_not_equal_data, __func__,
_("unexpected length of integrity code for %s file"), kp->data );
continue;
}
}
/* выполняем проверку конкретного файла */
aktool_icode_check_function( (const char *)kp->data, kp->data +kp->key_length );
}
while( ak_list_next( list ));
}
/* финальное предупреждение */
if( ki->statistical_data.skiped_files ) {
aktool_error(_("aktool found %d error(s), try aktool with \"--audit-file stderr --audit 2\""
" options or see syslog messages"), ki->statistical_data.skiped_files );
exit_status = EXIT_FAILURE;
}
else exit_status = EXIT_SUCCESS;
/* вывод статистики о проделанной работе */
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
if( !ki->quiet ) {
if( !ki->dont_show_stat ) {
if(( !ki->dont_show_icode ) || ( ki->statistical_data.skiped_files )) printf("\n");
printf(_("the total number of files checked: %llu, of which:\n"),
(long long unsigned int) ki->statistical_data.total_files );
printf(_(" %6llu have been proceed\n"),
(long long unsigned int) ki->statistical_data.hashed_files );
printf(_(" %6llu have been discarded\n"),
(long long unsigned int) ki->statistical_data.skiped_files );
if( ki->statistical_data.skiped_files ) {
printf(_(" %6llu have been deleted\n"),
(long long unsigned int) ki->statistical_data.deleted_files );
printf(_(" %6llu have been changed\n"),
(long long unsigned int) ki->statistical_data.changed_files );
}
}
}
return exit_status;
}
/* ----------------------------------------------------------------------------------------------- */
static int aktool_icode_check_file_function( const char *value, ak_pointer ptr )
{
ak_keypair kp = NULL;
aktool_ki_t *ki = ptr;
int error = ak_error_ok;
/* проверяем черный список */
if( ak_htable_get_str( &ki->exclude_file, value, NULL ) != NULL ) return ak_error_ok;
/* ищем файл в базе */
if(( kp = ak_htable_exclude_keypair_str( &ki->icodes, value )) == NULL ) {
ki->statistical_data.total_files++;
ki->statistical_data.new_files++;
if( !ki->quiet ) aktool_error( _("%s is a new file"), value );
return ak_error_message_fmt( ak_error_htable_key_not_found, __func__,
_("%s is a new file"), value );
}
/* проверяем, что база корректна */
if( kp->data == NULL ) {
ak_error_message( ak_error_null_pointer, __func__, _("using null pointer to keypair"));
goto labex;
}
/* выполняем проверку конкретного файла */
error = aktool_icode_check_function( (const char *)kp->data, kp->data +kp->key_length );
labex:
if( kp != NULL ) ak_keypair_delete( kp );
return error;
}
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_check_from_directory( aktool_ki_t *ki )
{
size_t total_errors = 0;
int exit_status = EXIT_FAILURE;
/* аудит */
if( ak_log_get_level() > ak_log_standard )
ak_error_message_fmt( ak_error_ok, __func__,
_("checking all files from selected catalogues"));
/* обнуляем счетчики */
memset( &ki->statistical_data, 0, sizeof( struct icode_stat ));
/* начинаем с обхода файлов */
if( ki->include_file.count ) {
ak_list_first( &ki->include_file );
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
do{
aktool_icode_check_file_function( ( char * )ki->include_file.current->data, ki );
} while( ak_list_next( &ki->include_file ));
}
/* теперь продолжаем обходом каталогов */
if( ki->include_path.count ) {
ak_list_first( &ki->include_path );
do{
const char *value = ( const char * )ki->include_path.current->data;
/* удаляем, при необходимости, обратный слэш */
if( strlen(value) > 1 ) {
size_t vlen = strlen( value );
if( value[vlen -1] == '/' ) ((char *)ki->include_path.current->data)[vlen-1] = 0;
}
/* проверяем черный список */
if( ak_htable_get_str( &ki->exclude_path, value, NULL ) != NULL ) continue;
/* запускаем вычисление контрольной суммы */
ak_file_find( value, ki->pattern, aktool_icode_check_file_function, ki, ki->tree );
} while( ak_list_next( &ki->include_path ));
/* осталось найти то, что осталось непроверенным */
if( ki->search_deleted ) {
for( size_t i = 0; i < ki->icodes.count; i++ ) {
ak_list list = &ki->icodes.list[i];
if( list->count == 0 ) continue;
ak_list_first( list );
do{
ak_keypair kp = (ak_keypair)list->current->data;
// printf(" - [key: %s, val: %s]\n", kp->data,
// ak_ptr_to_hexstr( kp->data + kp->key_length, kp->value_length, ak_false ));
if( kp->value_length == ki->size ) {
ki->statistical_data.total_files++;
ki->statistical_data.deleted_files++;
aktool_error(_("%s has been deleted"), kp->data );
ak_error_message_fmt( ak_error_file_exists, __func__, _("%s has been deleted"), kp->data );
}
} while( ak_list_next( list ));
}
} /* if( search_deleted ) */
} /* if( include_path ) */
/* финальное сообщение об ошибках */
total_errors = ki->statistical_data.skiped_files +
ki->statistical_data.deleted_files + ki->statistical_data.new_files;
if( total_errors ) {
exit_status = EXIT_FAILURE;
aktool_error(_("aktool found %d error(s), try aktool with \"--audit-file stderr --audit 2\""
" options or see syslog messages"), total_errors );
}
else exit_status = EXIT_SUCCESS;
/* вывод статистики о проделанной работе */
if( !ki->quiet ) {
if( !ki->dont_show_stat ) {
if(( !ki->dont_show_icode ) || ( ki->statistical_data.skiped_files )) printf("\n");
printf(_("the total number of files checked: %llu, of which:\n"),
(long long unsigned int) ki->statistical_data.total_files );
/* успешно проверены */
printf(_(" %6llu have been proceed\n"),
(long long unsigned int) ki->statistical_data.hashed_files );
/* проверка завершилась с ошибкой */
if( ki->statistical_data.deleted_files )
printf(_(" %6llu have been deleted\n"),
(long long unsigned int) ki->statistical_data.deleted_files );
if( ki->statistical_data.changed_files )
printf(_(" %6llu have been changed\n"),
(long long unsigned int) ki->statistical_data.changed_files );
if( ki->statistical_data.new_files )
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
printf(_(" %6llu new files found\n"),
(long long unsigned int) ki->statistical_data.new_files );
}
}
aktool_icode_destroy_handle( ki );
return exit_status;
}
#ifdef AK_HAVE_GELF_H
/* ----------------------------------------------------------------------------------------------- */
/* часть, отвечающая за проверку процессов в памяти */
/* ----------------------------------------------------------------------------------------------- */
static int aktool_icode_check_maps_segment( size_t length, ak_keypair kp, aktool_ki_t *ki )
{
struct file fm;
ak_uint8 ic2[128], *iptr = NULL;
ak_pointer dkey = NULL;
char fmemory[128], icode[128], buffer[4096];
/* формируем имя */
memset( fmemory, 0, sizeof( fmemory ));
ak_snprintf( fmemory, sizeof( fmemory ), "/proc/%d/mem", ki->pid );
/* открываем файл */
if( ak_file_open_to_read( &fm, fmemory ) != ak_error_ok ) {
ak_error_message_fmt( ak_error_access_file, __func__,
_("access to file %s is'nt granted"), fmemory );
return ak_error_ok;
}
/* вычисляем производный ключ */
if(( dkey = aktool_icode_get_derived_key( (char *)kp->data, ki, length )) == NULL ) {
ak_file_close( &fm );
aktool_error(_("incorrect creation of derived key for %s line"), kp->data );
return ak_error_message_fmt( ak_error_get_value(), __func__,
_("incorrect creation of derived key for %s line"), kp->data );
}
/* присоединяемся и блокируем процесс */
if( ptrace( PTRACE_ATTACH, ki->pid, NULL, NULL) < 0 ) {
ak_error_message_fmt( ak_error_access_file, __func__,
_("ptrace attach error: %s"), strerror( errno ));
goto labexit;
}
waitpid( ki->pid, NULL, 0 );
/* считываем данные небольшими фрагментами и формируем контрольную сумму */
lseek( fm.fd, ki->curmem.st_addr, SEEK_SET );
ki->icode_clean( dkey );
while( length > 0 ) {
size_t rlen = read( fm.fd, buffer, ak_min( length, sizeof( buffer )));
if( rlen == length ) { /* считали последний блок */
ki->icode_finalize( dkey, buffer, rlen, icode, ki->size );
}
else ki->icode_update( dkey, buffer, rlen );
length -= rlen;
}
/* отсоединяемся */
if( ptrace( PTRACE_DETACH, ki->pid, NULL, NULL) < 0 ) {
ak_error_message_fmt( ak_error_access_file, __func__,
_("ptrace detach error: %s"), strerror( errno ));
goto labexit;
}
/* сравниваем значения */
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
if( kp->value_length == ki->size +8 ) iptr = ( kp->data + kp->key_length + 8 );
else { /* здесь обрабатываем обычные (не elf) файлы */
if( ki->curmem.offset == 0 )
{
iptr = ( kp->data + kp->key_length );
}
else {
/* на месте вычисляем контрольную сумму от файла на диске */
ki->icode_file_offset( ki->handle,
(char *) kp->data, ki->curmem.offset, -1, ic2, ki->size );
iptr = ic2;
}
}
if( !ak_ptr_is_equal_with_log( icode, iptr, ki->size )) {
ki->statistical_data.skipped_segments++;
ak_error_message_fmt( ak_error_not_equal_data, __func__,
_("segment %s has been modified"), kp->data );
aktool_error(_("segment %s has been modified"), kp->data );
}
else {
if( ak_log_get_level() > ak_log_standard )
ak_error_message_fmt( ak_error_ok, __func__, _("segment %s is Ok"), kp->data );
}
labexit:
if( dkey != ki->handle ) ak_skey_delete( dkey );
ak_file_close( &fm );
return ak_error_ok;
}
/* ----------------------------------------------------------------------------------------------- */
static int rp_counter = 0;
static char old_name[FILENAME_MAX];
/* ----------------------------------------------------------------------------------------------- */
static int aktool_icode_check_maps_file_line( const char *buffer, ak_pointer inptr )
{
Elf *e;
char r, w, x, s, *ptr = NULL;
struct file fp;
ak_keypair kp = NULL;
size_t inode, flen = 0;
aktool_ki_t *ki = inptr;
int error = ak_error_ok; unsigned int major, minor;
char filename[FILENAME_MAX], segment_value[FILENAME_MAX];
/* базовые проверки */
if( ki == NULL ) return ak_error_null_pointer;
/* начинаем разбор параметров строки */
#ifdef AK_SIZEOF_VOID_P_IS_4
if( sscanf( buffer, "%x-%x %c%c%c%c %x %x:%x %u %s",
&ki->curmem.st_addr, &ki->curmem.en_addr, &r, &w, &x, &s, &ki->curmem.offset,
&major, &minor, &inode, filename ) < 11 ) {
#else
#ifdef AK_SIZEOF_VOID_P_IS_8
if( sscanf( buffer, "%lx-%lx %c%c%c%c %lx %x:%x %lu %s",
&ki->curmem.st_addr, &ki->curmem.en_addr, &r, &w, &x, &s, &ki->curmem.offset,
&major, &minor, &inode, filename ) < 11 ) {
#else
#error "Unsupported sizeof(void *) value"
#endif
#endif
if( inode != 0 || major != 0 || minor != 0 ) /* иначе это нулевая страница */
ak_error_message_fmt( ak_error_undefined_value, __func__,
_("process: %d, unexpected map's line %s"), ki->pid, buffer );
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
return ak_error_ok;
}
/* обрабатываем имена файлов с пробелами */
ptr = strstr( buffer, filename );
memset( filename, 0, sizeof( filename ));
ak_snprintf( filename, sizeof( filename ) -1, "%s", ptr );
/* обрабатываем флаги доступа */
if( r != 'r' ) {
if( s == 'p' ) ++rp_counter;
ak_error_message_fmt( ak_error_access_file, __func__,
_("process: %d, segment that cannot be read (line %s)"), ki->pid, buffer );
return ak_error_ok;
}
if( w == 'w' ) return ak_error_ok; /* сегмент с правами на запись */
if( memcmp( old_name, filename, strlen( filename )) == 0 ) { /* надо разобраться */
if(( r == 'r' ) && ( s == 'p' ) && ( x == '-' )) {
if( ++rp_counter > 1 ) {
rp_counter = 0;
return ak_error_ok;
}
}
} else {
rp_counter = 0;
memset( old_name, 0, sizeof(old_name));
strncpy( old_name, filename, sizeof( old_name ));
}
/* обрабатываем специальные сегменты */
if(( flen = strlen(filename)) == 0 ) {
ak_error_message_fmt( ak_error_zero_length, __func__,
_("process: %d, zero length of loaded file (line %s)"), ki->pid, buffer );
return ak_error_ok;
}
if( filename[0] == '[' ) {
if( flen < 2 ) {
ak_error_message_fmt( ak_error_wrong_length, __func__,
_("process: %d, short name of special segment (line %s)"), ki->pid, buffer );
return ak_error_ok;
}
filename[ strlen(filename) -1 ] = 0;
/* обработка специальных сегментов пока не реализована */
return ak_error_ok;
}
/* статистика */
ki->statistical_data.segments++;
/* проверяем, что файл не имеет структуру исполняемого файла (elf) */
if( ak_file_open_to_read( &fp, filename ) != ak_error_ok ) {
aktool_error(_("process: %d, link to non-existent file %s"), ki->pid, filename );
error = ak_error_message_fmt( ak_error_access_file, __func__,
_("process %d, link to non-existent file %s"), ki->pid, filename );
goto labexit;
}
if(( e = elf_begin( fp.fd, ELF_C_READ, NULL )) == NULL ) {
ak_file_close( &fp );
error = ak_error_message_fmt( ak_error_access_file, __func__,
_("process %d, elf_begin() function failed: %s"), ki->pid, elf_errmsg(-1));
goto labexit;
}
/* рассматриваем каждый случай отдельно */
if( elf_kind(e) != ELF_K_ELF ) {
if( ki->verbose ) {
printf(_("found file: %s\n"), filename );
}
/* проверяем, надо ли исключать данный файл */
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
if( ak_htable_get_keypair_str( &ki->exclude_link, filename ) != NULL ) {
if( ak_log_get_level() >= ak_log_maximum ) {
ak_error_message_fmt( ak_error_ok, __func__, "link to the file %s excluded", filename );
}
ki->statistical_data.skipped_links++;
goto exlabx;
}
if(( kp = ak_htable_get_keypair_str( &ki->icodes, filename )) == NULL ) {
aktool_error(_("process: %d, link to non-controlled file %s"), ki->pid, filename );
error = ak_error_message_fmt( ak_error_htable_key_not_found, __func__,
_("process: %d, link to non-controlled file %s"), ki->pid, filename );
}
else {
ak_int64 tmp;
if( ki->curmem.offset != 0 ) tmp = fp.size - ki->curmem.offset;
else tmp = fp.size;
error = aktool_icode_check_maps_segment( tmp, kp, ki );
}
}
else {
/* формируем строку для поиска */
ak_snprintf( segment_value, sizeof( segment_value ) -1,
"%s/%08x", filename, (unsigned int) ki->curmem.offset );
if( ki->verbose ) {
printf(_("found segment: %s\n"), segment_value );
}
if(( kp = ak_htable_get_keypair_str( &ki->icodes, segment_value )) == NULL ) {
aktool_error(_("process: %d, link to non-controlled segment %s"),
ki->pid, segment_value );
error = ak_error_message_fmt( ak_error_htable_key_not_found, __func__,
_("process: %d, link to non-controlled segment %s"), ki->pid, segment_value );
}
else {
size_t length = ((ak_uint64 *)(kp->data + kp->key_length))[0];
error = aktool_icode_check_maps_segment( length, kp, ki );
}
}
exlabx:
/* освобождаем память */
elf_end(e);
ak_file_close( &fp );
/* статистика */
labexit:
if( error != ak_error_ok )
ki->statistical_data.skipped_segments++;
return ak_error_ok;
}
/* ----------------------------------------------------------------------------------------------- */
/*! номер обрабатываемого процесса (pid) передается в переменной ki->pid */
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_check_process_with_pid( aktool_ki_t *ki )
{
struct file fp;
int error = ak_error_ok;
char cat[128], filename[128];
/* очищаем текущее значение ошибки */
ak_error_set_value( ak_error_ok );
/* формируем имя каталога, который будет использоваться далее */
memset( cat, 0, sizeof( cat ));
ak_snprintf( cat, sizeof(cat), "/proc/%d", ki->pid );
if( ak_log_get_level() > ak_log_standard )
ak_error_message_fmt( ak_error_ok, __func__, _("checking the pid %llu"),
(long long unsigned int) ki->pid );
/* статистика */
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
ki->statistical_data.processes++;
/* проверяем права доступа */
switch( ak_file_or_directory(cat) ) {
case ak_error_access_file:
ki->statistical_data.skipped_processes++;
aktool_error("access to catalog %s is not granted (%s)", cat, strerror( errno ));
ak_error_message_fmt( ak_error_access_file, __func__,
"access to catalog %s is not granted (%s)", cat, strerror( errno ));
return EXIT_FAILURE;
case DT_REG:
ki->statistical_data.skipped_processes++;
aktool_error("checkin' a regular file %s", cat );
ak_error_message_fmt( ak_error_not_directory, __func__,
"checkin' a regular file %s", cat );
return EXIT_FAILURE;
default:
break;
}
/* формируем имя файла с картой адресов памяти */
memset( filename, 0, sizeof( filename ));
ak_snprintf( filename, sizeof(filename), "%s/maps", cat );
/* получаем карту адресов памяти для контроля */
if( ak_file_open_to_read( &fp, filename ) != ak_error_ok ) {
ki->statistical_data.skipped_processes++;
aktool_error("file %s can't be opened (%s)", cat, strerror( errno ));
ak_error_message_fmt( ak_error_open_file, __func__,
"file %s can't be opened (%s)", cat, strerror( errno ));
return EXIT_FAILURE;
}
/* подготавливаем внутренние переменные */
memset( &ki->curmem, 0, sizeof( memaddr_t ));
memset( old_name, 0, sizeof( old_name ));
/* построчно считываем данные и выполняем проверку */
error = ak_file_read_by_lines( filename, aktool_icode_check_maps_file_line, ki );
ak_file_close( &fp );
if(( error != ak_error_ok ) || ( ak_error_get_value() != ak_error_ok )) {
ki->statistical_data.skipped_processes++;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/* ----------------------------------------------------------------------------------------------- */
int aktool_icode_check_processes( aktool_ki_t *ki )
{
DIR *dp = NULL;
pid_t mypid = getpid();
struct dirent *ent = NULL;
int exit_status = EXIT_FAILURE;
struct list pids;
/* обнуляем статистику */
ki->statistical_data.processes =
ki->statistical_data.skipped_processes =
ki->statistical_data.skipped_links =
ki->statistical_data.segments =
ki->statistical_data.skipped_segments = 0;
/* тестируем только один процесс */
if( ki->pid != -1 ) {
exit_status = aktool_icode_check_process_with_pid( ki );
goto labstat;
}
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
/* последовательно тестируем все найденные процессы */
errno = 0;
if(( dp = opendir( "/proc" )) == NULL ) {
if( errno == EACCES ) {
ak_error_message_fmt( ak_error_access_file,
__func__ , "access to /proc directory denied" );
goto labstat;
}
if( errno > -1 )
ak_error_message_fmt( ak_error_open_file, __func__ , "%s", strerror( errno ));
goto labstat;
}
/* перебираем все файлы и каталоги */
ak_list_create( &pids );
while(( ent = readdir( dp )) != NULL ) {
if( ent->d_type != DT_DIR ) continue;
if( !strcmp( ent->d_name, "." )) continue; // пропускаем себя и каталог верхнего уровня
if( !strcmp( ent->d_name, ".." )) continue;
if(( ki->pid = atol( ent->d_name )) > 0 ) {
/* себя, как процесс, пропускаем */
if(( ki->pid >= ki->min_pid ) && ( ki->pid <= ki->max_pid ) && ( ki->pid != mypid )) {
ak_list_add_node( &pids, ak_list_node_new( malloc( sizeof( pid_t ))));
((pid_t *)pids.current->data)[0] = ki->pid;
}
}
}
closedir( dp );
/* обрабатываем найденные процессы */
if( pids.count > 0 ) {
ak_list_first( &pids );
do{
ki->pid = ((pid_t *)pids.current->data)[0];
exit_status = aktool_icode_check_process_with_pid( ki );
} while( ak_list_next( &pids ));
}
ak_list_destroy( &pids );
/* вывод статистики о проделанной работе */
labstat:
if( !ki->quiet ) {
if( !ki->dont_show_stat ) {
printf(_("the total number of processes checked: %llu, of which\n"),
(long long unsigned int) ki->statistical_data.processes );
printf(_(" %6llu have been succesfully proceed\n"),
(long long unsigned int)( ki->statistical_data.processes
- ki->statistical_data.skipped_processes ));
/* проверка завершилась с ошибкой */
if( ki->statistical_data.skipped_processes )
printf(_(" %6llu have been skipped\n"),
(long long unsigned int) ki->statistical_data.skipped_processes );
printf(_(" %6llu the total founded segments\n"),
(long long unsigned int) ki->statistical_data.segments );
/* проверка завершилась с ошибкой */
if( ki->statistical_data.skipped_segments )
printf(_(" %6llu segments have been skipped\n"),
(long long unsigned int) ki->statistical_data.skipped_segments );
/* сознательно пропущенные ссылки на файлы */
if( ki->statistical_data.skipped_links )
printf(_(" %6llu links have been excluded\n"),
(long long unsigned int) ki->statistical_data.skipped_links );
}
}
return exit_status;
1051105210531054105510561057
}
#endif
/* ----------------------------------------------------------------------------------------------- */
/* aktool_icode_evaluate.c */
/* ----------------------------------------------------------------------------------------------- */