#!/usr/bin/perl
use Digest::MD5::File qw(file_md5_hex);
use strict;
use warnings;
use DB_File;
use Getopt::Std;
use Net::XMPP;
#Config:
my $j_host = "s-teals.info";
my $j_login = "bot";
my $j_pass = "pass";
my $j_adm = 'timofei1394@s-teals.info';
my $command = 'who,ps';
my $logfile = 'mdval.log';
my %opts;
#r - рекурсия (bool), n- флаг создания новой базы (bool), i - инпут, хуле (имя новой базы или имя той которую чекаем),
#v - подробный вывод при создании базы (bool), o - отпут, имя новой базы стало быть, с - флаг чека базы. a- проверка
#на новые файлы (bool)
getopts("vncari:o:",\%opts);
if($opts{n}){
if($opts{i} and $opts{o}){
gen_db($opts{i},$opts{o},$opts{r},$opts{v});
}
}
if($opts{c}){
check($opts{i});
}
help();
#$exist_f - отсутствующие в директории файлы
#$mdfailed_f - файлы с которыми не совпала контрольная сумма
#$command_result - вывод комманд заданых в конфиге в переменной $command
#$new_f - новые файлы в подконтрольной дире
sub check{
logw("Cheking start");
my(%db,$exist_f,$md5failed_f,$new_f,$command_result);
dbmopen(%db,"$_[0]", 0777) or logw("Check error: $!\n");
while(my($path,$md5_db) = each %db){
unless(-e $path){
$exist_f .= "$path\n" if("$path" ne 'dir' and "$path" ne 'recursive'); #Исключаем dir и recursive из путей.
} else {
my $md5_new = get_md($path);
unless($md5_new eq $md5_db){
$md5failed_f .= "\n$path\nMD5 Old:$md5_db\nMD5 New:$md5_new\n";
}
}
}
if($opts{a}){
my @ch_file_list = scan_dir($db{dir},$db{recursive});
for(my $i=0;@ch_file_list>$i;$i++){
$ch_file_list[$i] =~ s/\/\//\//g;
unless($db{$ch_file_list[$i]}){
$new_f .= $ch_file_list[$i];
}
}
}
dbmclose(%db);
if($command){
my @command = split(',',$command);
$command_result .= "$command:\n";
for(my $i=0;@command>$i;$i++){
$command_result .= `$command[$i]`."\n";
}
}
if($md5failed_f or $new_f or $exist_f){
jabber_send($j_adm,"\nFailedMD5:\n$md5failed_f\nNewFile:\n$new_f\nExistFile:\n$exist_f\nCommand_Result:\n$command_result");
}
logw("Check finish");
exit(0);
}
#Осторожно! Рекурсия =)
sub scan_dir{
my @list;
my $recursive = $_[1];
my $dir = $_[0];
for my $file (glob($dir.'/*')){
unless(-d $file){
push @list, $file;
} else {
if($recursive){
$file =~ s/ /\\ /g;
my @sub = scan_dir($file,$recursive);
push @list, @sub;
}
}
}
return @list;
}
sub get_md{
my $digest;
$digest = file_md5_hex("$_[0]");
return($digest);
}
sub gen_db{
logw("Generation DB starting");
my (@file_list,%result);
@file_list = scan_dir($_[0],$_[2]);
if(-e $_[1]){
print "$_[1] already exist. Overwrite it? \[y\\n\]\n";
while(<STDIN>){
chop $_;
if($_ eq ''){print "Bye-bye\n";exit(0);}
if($_ eq 'y' or $_ eq 'Y'){unlink("$_[1]") or die "Error: $!";last;}
if($_ eq 'n' or $_ eq 'N'){print "Bye-bye\n";exit(0);}
}
}
dbmopen(%result,"$_[1]", 0777);
($result{recursive},$result{dir}) = ($_[2],$_[0]);
for(my $i=0;@file_list>$i;$i++){
my $md5= get_md($file_list[$i]);
$file_list[$i] =~ s/\/\//\//g;
$file_list[$i] =~ s/\n|\r//g;
$md5 =~ s/\n|\r//;
if($_[3]){
print "File: $file_list[$i]\n MD5:$md5\n";
}
$result{$file_list[$i]} = $md5;
}
dbmclose(%result);
logw("Generation DB finish");
exit(0);
}
sub jabber_send {
logw("Sending message to jabber");
my $cnx = new Net::XMPP::Client(debuglevel=>0);
$cnx->Connect(hostname => "$j_host", tls => 0);
$cnx->AuthSend('hostname' => "$j_host",
'username' => "$j_login",
'password' => "$j_pass",
'resource' => "Oo");
$cnx->MessageSend('to' => "$_[0]",
'type'=>"chat",
'body' => "$_[1]");
$cnx->Disconnect();
}
sub logw {
my $log_msg = shift;
my $now_time = localtime time;
open(LOG,">> $logfile");
print LOG "\[$now_time\]: $log_msg\n";
close(LOG);
}
sub help {
print <<HELP;
System of control integrity files by s-teals.org
Use:
perl $0 <keys>
Keys:
-n - Create new database with checksum files
Keys that can be used with -n:
-r - Recursive walk directory
-i <path> - path to directory with checksum files
-o <path> - path to saving database with checksums files
-v - Advanced output at create database (warning many letters)
-c - verifying checksum files by database
Keys that can be used with -c:
-i <path> - path to database with checksum
-a - verifying new files in control directory
Example:
perl $0 -nr -i /etc -o etc.db - create database with checksum files directiry /etc with recursive walk directory
perl $0 -c -i etc.db - verifying checksum files by database etc.db without verifying new files in control directory
HELP
exit(0);
}