#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - scripts/check_security_advice_changes Copyright 2018 cPanel L.L.C.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
package scripts::check_security_advice_changes;
use strict;
use Cpanel::Transaction::File::JSON ();
use Cpanel::Hash ();
use Cpanel::Locale ();
use Cpanel::Usage ();
use Cpanel::Alarm ();
use Capture::Tiny ();
my $WANT_TYPE = 'mod_advice';
my $CHANNEL = 'securityadvisor';
our $HISTORY_FILE = '/var/cpanel/security_advisor_history.json';
_run_from_command_line(@ARGV) if !caller();
sub _run_from_command_line {
my (@args) = @_;
if ( grep { index( $_, '-background' ) > -1 } @args ) {
@args = grep { index( $_, '-background' ) != -1 } @args;
require Cpanel::Daemonizer::Tiny;
require Cpanel::FileUtils::Open;
require Cpanel::ConfigFiles;
my $pid = Cpanel::Daemonizer::Tiny::run_as_daemon(
sub {
####
# The next two calls are unchecked because it cannot be captured when running as a daemon
no warnings 'once';
Cpanel::FileUtils::Open::sysopen_with_real_perms( \*STDERR, $Cpanel::ConfigFiles::CPANEL_ROOT . '/logs/error_log', 'O_WRONLY|O_APPEND|O_CREAT', 0600 );
open( STDOUT, '>&', \*STDERR ) || warn "Failed to redirect STDOUT to STDERR";
return _exit( __PACKAGE__->script( \@args ) );
}
);
return _exit(0);
}
return _exit( __PACKAGE__->script( \@args ) );
}
sub _exit {
my ($code) = @_;
return exit($code);
}
sub script {
my ( $class, $argv ) = @_;
my %opts = (
notify => 0,
quiet => 0,
);
my $self = bless {}, $class;
Cpanel::Usage::wrap_options(
$argv,
sub { my (@args) = @_; $self->usage(@args); },
{ 'notify' => \$opts{'notify'}, 'quiet' => \$opts{'quiet'} },
);
$self->{'notify'} = $opts{'notify'};
$self->{'quiet'} = $opts{'quiet'};
local $Cpanel::Locale::Context::DEFAULT_OUTPUT_CONTEXT = 'html';
# The yum calls can take a while if yum is in use so we now
# wait up to 30m. Since v78+ does the security advisor
# checks in the background this should be ok now.
my $main_alarm = Cpanel::Alarm->new( 1800, sub { die "$0 timed out because it was running for longer then 30 minutes."; } ); #max 30m
my $trans_obj = Cpanel::Transaction::File::JSON->new( 'path' => $HISTORY_FILE );
my $previous_run = $trans_obj->get_data();
my %hashes = ( ref $previous_run eq 'HASH' and $previous_run->{'hashes'} ) ? %{ $previous_run->{'hashes'} } : ();
my %message_keys = ( ref $previous_run eq 'HASH' and $previous_run->{'message_keys'} ) ? %{ $previous_run->{'message_keys'} } : ();
require Cpanel::Security::Advisor;
require Cpanel::Security::AdvisorFetch;
my $msgs = Cpanel::Security::AdvisorFetch::fetch_security_advice();
my $highest_notice_type = 0;
my %notices;
foreach my $data ( @{$msgs} ) {
my $block = ( $data->{'advice'}{'block_notify'} ) ? $data->{'advice'}{'block_notify'} : 0;
if ( $data->{'type'} eq $WANT_TYPE && !$block ) {
my $module = $data->{'module'};
my $text = $data->{'advice'}{'text'} . ( $data->{'advice'}{'suggestion'} ? " " . $data->{'advice'}{'suggestion'} : '' );
my $hash = Cpanel::Hash::get_fastest_hash($text);
my $message_key = ( $data->{'advice'}{'key'} ) ? $data->{'advice'}{'key'} : $data->{'module'};
# NOTE: Condition description:
# NOTE: True If advice type is INFO/WARN/BAD && (advice not seen before (via static key or hash) or advise type is greater [i.e., worse] then seen type)
my $good = Cpanel::Security::Advisor::_lookup_advise_type_by_value(q{ADVISE_GOOD});
if ( $data->{'advice'}{'type'} > $good && ( !( $hashes{$hash} || $message_keys{$message_key} ) || $hashes{$hash} < $data->{'advice'}{'type'} ) ) {
push @{ $notices{$module} }, $data->{'advice'};
if ( $highest_notice_type < $data->{'advice'}{'type'} ) {
$highest_notice_type = $data->{'advice'}{'type'};
}
}
# maintain the augmented datastructure
$hashes{$hash} = $data->{'advice'}{'type'};
# message key hash will store advise type as string
$message_keys{$message_key}{$hash} = Cpanel::Security::Advisor::_lookup_advise_type( $data->{'advice'}{'type'} );
}
}
$trans_obj->set_data( { 'hashes' => \%hashes, 'message_keys' => \%message_keys } );
my ( $status, $statusmsg ) = $trans_obj->save_and_close();
# Need to notify
{
no warnings 'once';
if (
$highest_notice_type
&&
# case CPANEL-6053: Only generate an iContact notification if there
# are changes to WARN or higher.
$highest_notice_type >= $Cpanel::Security::Advisor::ADVISE_WARN
) {
$self->notify( $highest_notice_type, \%notices );
}
else {
print $self->_locale()->maketext("There are no changes to the Security Advisor state that require notification.") . "\n";
}
}
return 0;
}
sub usage {
my ($self) = @_;
print $self->_locale()->maketext(q{This tool monitors the state of the Security Advisor and can send a notification when the state changes.}), "\n\n";
print $self->_locale()->maketext( q{Usage: [_1][comment,a program name] ~[options~]}, $0 ), "\n\n";
print $self->_locale()->maketext(q{Options:}), "\n";
print "\t--help ", $self->_locale()->maketext(q{Display this help message.}), "\n";
print "\t--notify ", $self->_locale()->maketext(q{Send a notification to the system administrator.}), "\n";
print "\t--quiet ", $self->_locale()->maketext(q{Do not display output, and instead set the [output,asis,UNIX] exit code.}), "\n\n";
exit 0;
}
sub notify {
my ( $self, $highest_notice_type, $notices ) = @_;
require Cpanel::Locale;
my $old = $self->_locale()->set_context_plain();
require Cpanel::Notify;
my $ic_obj = Cpanel::Notify::notification_class(
'class' => 'Check::SecurityAdvisorStateChange',
'application' => 'Check::SecurityAdvisorStateChange',
'status' => 'changes',
'interval' => 1,
'constructor_args' => [
'origin' => 'check_for_security_advise_changes',
'notices' => $notices,
'highest_notice_type' => $highest_notice_type,
'skip_send' => 1,
]
);
unless ( $self->{'quiet'} ) {
print $ic_obj->render_template_include_as_text( 'template' => 'subject', 'type' => 'text' ) . "\n\n" . $ic_obj->render_template_include_as_text( 'template' => 'body', 'type' => 'html' );
}
if ( $self->{'notify'} ) {
$ic_obj->send();
}
$self->_locale()->set_context($old);
return 1;
}
sub _locale {
my ($self) = @_;
require Cpanel::Locale;
return ( $self->{'_locale'} ||= Cpanel::Locale->get_handle() );
}
1;
Copyright 2K16 - 2K18 Indonesian Hacker Rulez