From 1b3c9db30d8832d9c893927f11b1047db8b48497 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Tue, 20 Feb 2018 17:45:51 +0100 Subject: [PATCH 01/15] [Linux Agent] Added cron functions and remove cron_module_interval --- pandora_agents/unix/pandora_agent | 399 ++++++++++++++++++++++++------ 1 file changed, 325 insertions(+), 74 deletions(-) diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 30e695f542..fe0b9908b6 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -30,6 +30,7 @@ use File::Basename; use File::Copy; use IO::Socket; use Sys::Syslog; +use Time::Local; # Agent XML data my $Xml; @@ -515,10 +516,11 @@ sub parse_conf_modules($) { } } } elsif ($line =~ /^\s*module_crontab\s+(((\*|(\d+(-\d+){0,1}))\s*){5}).*$/) { - $module->{'cron'} = $1; - chomp ($module->{'cron'}); - } elsif ($line =~ /^\s*module_cron_interval\s+(\d+).*$/) { - $module->{'cron_interval'} = $1; + my $cron_text = $1; + chomp ($cron_text); + if (cron_check_syntax($cron_text)) { + $module->{'cron'} = $cron_text; + } } elsif ($line =~ /^\s*module_end\s*$/) { $module_begin = 0; @@ -1632,8 +1634,8 @@ sub guess_os_version ($) { ################################################################################ # Execute the given module. ################################################################################ -sub exec_module ($) { - my $module = shift; +sub exec_module { + my ($module, $interval) = @_; # Need something to execute if ($module->{'func'} == 0) { @@ -1648,7 +1650,7 @@ sub exec_module ($) { } # Check module cron - if (check_module_cron ($module) != 1) { + if (check_module_cron ($module, $interval) != 1) { $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); return; } @@ -2044,85 +2046,335 @@ sub evaluate_module_intensive_conditions ($$) { return 1; } +############################################################################### +# Get the number of seconds left to the next execution of the given cron entry. +############################################################################### +sub cron_next_execution { + my ($cron, $interval) = @_; + + # Check cron conf format + if ($cron !~ /^((\*|(\d+(-\d+){0,1}))\s*){5}$/) { + return $interval; + } + + # Get day of the week and month from cron config + my ($mday, $wday) = (split (/\s/, $cron))[2, 4]; + + # Get current time and day of the week + my $cur_time = time(); + my $cur_wday = (localtime ($cur_time))[6]; + + # Any day of the week + if ($wday eq '*') { + my $nex_time = cron_next_execution_date ($cron, $cur_time, $interval); + return $nex_time - time(); + } + # A range? + else { + $wday = cron_get_closest_in_range ($cur_wday, $wday); + } + + # A specific day of the week + my $count = 0; + my $nex_time = $cur_time; + do { + $nex_time = cron_next_execution_date ($cron, $nex_time, $interval); + my $nex_time_wd = $nex_time; + my ($nex_mon, $nex_wday) = (localtime ($nex_time_wd))[4, 6]; + my $nex_mon_wd; + do { + # Check the day of the week + if ($nex_wday == $wday) { + return $nex_time_wd - time(); + } + + # Move to the next day of the month + $nex_time_wd += 86400; + ($nex_mon_wd, $nex_wday) = (localtime ($nex_time_wd))[4, 6]; + } while ($mday eq '*' && $nex_mon_wd == $nex_mon); + $count++; + } while ($count < 60); + + # Something went wrong, default to 5 minutes + return $interval; +} + +############################################################################### +# Get the number of seconds left to the next execution of the given cron entry. +############################################################################### +sub cron_check_syntax ($) { + my ($cron) = @_; + + return 0 if !defined ($cron); + return ($cron =~ m/^(\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+ (\d|\*|-)+$/); +} + +############################################################################### +# Get the next execution date for the given cron entry in seconds since epoch. +############################################################################### +sub cron_next_execution_date { + my ($cron, $cur_time, $interval) = @_; + + # Get cron configuration + my ($min, $hour, $mday, $mon, $wday) = split (/\s/, $cron); + + # Months start from 0 + if($mon ne '*') { + my ($mon_down, $mon_up) = cron_get_interval ($mon); + if (defined($mon_up)) { + $mon = ($mon_down - 1) . "-" . ($mon_up - 1); + } else { + $mon = $mon_down - 1; + } + } + + # Get current time + if (! defined ($cur_time)) { + $cur_time = time(); + } + # Check if current time + interval is on cron too + my $nex_time = $cur_time + $interval; + my ($cur_min, $cur_hour, $cur_mday, $cur_mon, $cur_year) + = (localtime ($nex_time))[1, 2, 3, 4, 5]; + + my @cron_array = ($min, $hour, $mday, $mon); + my @curr_time_array = ($cur_min, $cur_hour, $cur_mday, $cur_mon); + return ($nex_time) if cron_is_in_cron(\@cron_array, \@curr_time_array) == 1; + + # Get first next date candidate from next cron configuration + # Initialize some vars + my @nex_time_array = @curr_time_array; + + # Update minutes + my ($min_down, undef) = cron_get_interval ($min); + $nex_time_array[0] = ($min_down eq '*') ? 0 : $min_down; + + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time >= $cur_time) { + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + } + + # Check if next hour is in cron + $nex_time_array[1]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + + if ($nex_time == 0) { + #Update the month day if overflow + $nex_time_array[1] = 0; + $nex_time_array[2]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time == 0) { + #Update the month if overflow + $nex_time_array[2] = 1; + $nex_time_array[3]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time == 0) { + #Update the year if overflow + $cur_year++; + $nex_time_array[3] = 0; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + } + } + } + + #Check the hour + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + + #Update the hour if fails + my ($hour_down, undef) = cron_get_interval ($hour); + $nex_time_array[1] = ($hour_down eq '*') ? 0 : $hour_down; + + # When an overflow is passed check the hour update again + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time >= $cur_time) { + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + } + + # Check if next day is in cron + $nex_time_array[2]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time == 0) { + #Update the month if overflow + $nex_time_array[2] = 1; + $nex_time_array[3]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time == 0) { + #Update the year if overflow + $nex_time_array[3] = 0; + $cur_year++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + } + } + + #Check the day + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + + #Update the day if fails + my ($mday_down, undef) = cron_get_interval ($mday); + $nex_time_array[2] = ($mday_down eq '*') ? 1 : $mday_down; + + # When an overflow is passed check the hour update in the next execution + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time >= $cur_time) { + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + } + + # Check if next month is in cron + $nex_time_array[3]++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time == 0) { + #Update the year if overflow + $nex_time_array[3] = 0; + $cur_year++; + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + } + + #Check the month + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + + #Update the month if fails + my ($mon_down, undef) = cron_get_interval ($mon); + $nex_time_array[3] = ($mon_down eq '*') ? 0 : $mon_down; + + # When an overflow is passed check the hour update in the next execution + $nex_time = cron_valid_date(@nex_time_array, $cur_year); + if ($nex_time >= $cur_time) { + return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); + } + + $nex_time = cron_valid_date(@nex_time_array, $cur_year + 1); + + return $nex_time; +} + +############################################################################### +# Returns if a date is in a cron. Recursive. +# Needs the cron like an array reference and +# current time in cron format to works properly +############################################################################### +sub cron_is_in_cron { + my ($elems_cron, $elems_curr_time) = @_; + + my @deref_elems_cron = @$elems_cron; + my @deref_elems_curr_time = @$elems_curr_time; + + my $elem_cron = shift(@deref_elems_cron); + my $elem_curr_time = shift (@deref_elems_curr_time); + + #If there is no elements means that is in cron + return 1 unless (defined($elem_cron) || defined($elem_curr_time)); + + # Go to last element if current is a wild card + if ($elem_cron ne '*') { + my ($down, $up) = cron_get_interval($elem_cron); + # Check if there is no a range + return 0 if (!defined($up) && ($down != $elem_curr_time)); + # Check if there is on the range + if (defined($up)) { + if ($down < $up) { + return 0 if ($elem_curr_time < $down || $elem_curr_time > $up); + } else { + return 0 if ($elem_curr_time > $down || $elem_curr_time < $up); + } + } + } + return cron_is_in_cron(\@deref_elems_cron, \@deref_elems_curr_time); +} + +############################################################################### +# Returns the interval of a cron element. If there is not a range, +# returns an array with the first element in the first place of array +# and the second place undefined. +############################################################################### +sub cron_get_interval { + my ($element) = @_; + + # Not a range + if ($element !~ /(\d+)\-(\d+)/) { + return ($element, undef); + } + + return ($1, $2); +} + +############################################################################### +# Returns the closest number to the target inside the given range (including +# the target itself). +############################################################################### +sub cron_get_closest_in_range ($$) { + my ($target, $range) = @_; + + # Not a range + if ($range !~ /(\d+)\-(\d+)/) { + return $range; + } + + # Search the closes number to the target in the given range + my $range_start = $1; + my $range_end = $2; + + # Outside the range + if ($target <= $range_start || $target > $range_end) { + return $range_start; + } + + # Inside the range + return $target; +} + +############################################################################### +# Check if a date is valid to get timelocal +############################################################################### +sub cron_valid_date { + my ($min, $hour, $mday, $month, $year) = @_; + my $utime; + eval { + local $SIG{__DIE__} = sub {}; + $utime = timelocal(0, $min, $hour, $mday, $month, $year); + }; + if ($@) { + return 0; + } + return $utime; +} + ################################################################################ # Checks the module's cron string. Returns 1 if the module should be run, 0 if # not. ################################################################################ -sub check_module_cron ($) { - my $module = shift; +sub check_module_cron { + my ($module, $main_interval) = @_; # No cron string defined return 1 unless ($module->{'cron'} ne ''); + my $now = time(); + # Check if the module was already executed - return 0 unless (time() >= $module->{'cron_utimestamp'}); + return 0 unless ($now >= $module->{'cron_utimestamp'}); - # Get cron configuration - my @cron_params = split (/\s/, $module->{'cron'}); + my $interval = $main_interval * $module->{'interval'}; - # Get current time - my $current_time = time(); - my @time = localtime($current_time); - - # Minutes, hours, day of the month, month and day of the week - my @time_params = @time[1, 2, 3, 4, 6]; - - # Fix month (localtime retuns 0..11 and we need 1..12) - $time_params[3] += 1; + $module->{'cron_utimestamp'} = $now + cron_next_execution( + $module->{'cron'}, + $interval + ); - # Check cron parameters - for (my $i = 0; $i < 5; $i++) { - - # Wildcard - next if ($cron_params[$i] eq '*'); - - # Get interval - my ($bottom, $top) = split (/-/, $cron_params[$i]); - $top = $bottom unless defined ($top); - - # Check if next execution will overflow the cron (only minutes overflow) - # If overflow, execute the module - my $overflow_cron = 0; - if ($i == 0) { - my $start_cron_seconds = $bottom*60; - my $current_exec_seconds = $time_params[$i]*60; - my $next_exec_seconds = $time_params[$i]*60 + $module->{'interval'}*$Conf{'interval'}; - if ($current_exec_seconds > $start_cron_seconds && $current_exec_seconds > $next_exec_seconds) { - $start_cron_seconds += 3600; - } - if (($current_exec_seconds <= $start_cron_seconds) && ($start_cron_seconds <= $next_exec_seconds)) { - $overflow_cron = 1 - } - } - - # Check interval - if ($bottom <= $top) { - return 0 if (($time_params[$i] < $bottom || $time_params[$i] > $top) && !$overflow_cron); - } else { - return 0 if (($time_params[$i] < $bottom && $time_params[$i] > $top) && !$overflow_cron); - } + if ($Conf{'debug'} eq '1') { + log_message ('debug', "Cron for module $module->{'name'} will be executed next time at timestamp: $module->{'cron_utimestamp'}."); } - # Do not check in the next minute, hour, day or month. - my $offset = 0; - if ($module->{'cron_interval'} >= 0) { - $offset = $module->{'cron_interval'}; - } elsif($cron_params[0] ne '*') { - # 1 minute - $offset = 60; - } elsif($cron_params[1] ne '*') { - # 1 hour - $offset = 3600; - } elsif($cron_params[2] ne '*' || $cron_params[4] ne '*') { - # 1 day - $offset = 86400; - } elsif($cron_params[3] ne '*') { - # 31 days - $offset = 2678400; - } + # On first execution checking if cron is valid is required + return 1 unless ($module->{'cron_utimestamp'} == 0); - $module->{'cron_utimestamp'} = $current_time + $offset; - return 1; + # Check if current timestamp is a valid cron date + my $next_execution = cron_next_execution_date( + $module->{'cron'}, + $now - $interval, + $interval + ); + return 1 if ($next_execution == $now); + return 0; } ################################################################################ @@ -2461,7 +2713,6 @@ sub init_module ($) { $module->{'conditions'} = []; $module->{'cron'} = ''; $module->{'cron_utimestamp'} = 0; - $module->{'cron_interval'} = -1; $module->{'precondition'} = []; $module->{'is_intensive'} = 0; $module->{'intensive_conditions'} = []; @@ -2770,7 +3021,7 @@ while (1) { # Execute the module in a separate thread if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1) { $ThreadSem->down (); - my $thr = threads->create (\&exec_module, $module); + my $thr = threads->create (\&exec_module, $module, $Conf{'interval'}); if (! defined ($thr)) { $ThreadSem->up (); } else { @@ -2778,7 +3029,7 @@ while (1) { } # Execute the module } else { - exec_module($module); + exec_module($module, $Conf{'interval'}); } } From cedf8255265baad9024de467320f2e8dce0752e1 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Tue, 20 Feb 2018 18:31:08 +0100 Subject: [PATCH 02/15] [Server] [Linux Agent] Added cron_interval to modules XML to avoid cron blocked modules go to unknown --- pandora_agents/unix/pandora_agent | 8 ++++++-- pandora_server/lib/PandoraFMS/DataServer.pm | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index fe0b9908b6..32a66facea 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -2355,10 +2355,13 @@ sub check_module_cron { my $interval = $main_interval * $module->{'interval'}; - $module->{'cron_utimestamp'} = $now + cron_next_execution( + my $time_to_next_execution = cron_next_execution( $module->{'cron'}, $interval ); + + $module->{'cron_utimestamp'} = $now + $time_to_next_execution; + $module->{'cron_interval'} = $time_to_next_execution; if ($Conf{'debug'} eq '1') { log_message ('debug', "Cron for module $module->{'name'} will be executed next time at timestamp: $module->{'cron_utimestamp'}."); @@ -2474,8 +2477,9 @@ sub write_module_xml ($@) { # Module Alert template $Xml .= " " . $module->{'alert_template'} . "\n" if (defined ($module->{'alert_template'})); - # Module Alert template + # Module Crontab $Xml .= " " . $module->{'cron'} . "\n" if (defined ($module->{'cron'}) and ($module->{'cron'} ne "")); + $Xml .= " " . $module->{'cron_interval'} . "\n" if (defined ($module->{'cron'}) and (defined ($module->{'cron_interval'}))); # FF threshold configuration $Xml .= " " . $module->{'min_ff_event_normal'} . "\n" if (defined ($module->{'min_ff_event_normal'})); diff --git a/pandora_server/lib/PandoraFMS/DataServer.pm b/pandora_server/lib/PandoraFMS/DataServer.pm index dab25b57e6..832f6451fc 100644 --- a/pandora_server/lib/PandoraFMS/DataServer.pm +++ b/pandora_server/lib/PandoraFMS/DataServer.pm @@ -611,7 +611,7 @@ sub process_module_data ($$$$$$$$$$) { 'unknown_instructions' => '', 'tags' => '', 'critical_inverse' => 0, 'warning_inverse' => 0, 'quiet' => 0, 'module_ff_interval' => 0, 'alert_template' => '', 'crontab' => '', 'min_ff_event_normal' => 0, 'min_ff_event_warning' => 0, 'min_ff_event_critical' => 0, 'ff_timeout' => 0, 'each_ff' => 0, 'module_parent' => 0, - 'module_parent_unlink' => 0}; + 'module_parent_unlink' => 0, 'cron_interval' => 0}; # Other tags will be saved here $module_conf->{'extended_info'} = ''; @@ -644,8 +644,12 @@ sub process_module_data ($$$$$$$$$$) { delete $module_conf->{'name'}; # Calculate the module interval in seconds - $module_conf->{'module_interval'} = 1 unless defined ($module_conf->{'module_interval'}); - $module_conf->{'module_interval'} *= $interval if (defined ($module_conf->{'module_interval'})); + if (defined($module_conf->{'cron_interval'})) { + $module_conf->{'module_interval'} = 1 unless defined ($module_conf->{'module_interval'}); + $module_conf->{'module_interval'} *= $interval if (defined ($module_conf->{'module_interval'})); + } else { + $module_conf->{'module_interval'} = $module_conf->{'cron_interval'}; + } # Allow , as a decimal separator $module_conf->{'post_process'} =~ s/,/./ if (defined ($module_conf->{'post_process'})); From 40ca8afe3774906d12997f6a43012502d82fbec2 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 11:58:28 +0100 Subject: [PATCH 03/15] [Windows Agent] Added separated class to manage cron (only constructor implemented) --- pandora_agents/win32/Makefile.am | 4 +- pandora_agents/win32/misc/cron.cc | 73 +++++++++++++++++++++++++++++++ pandora_agents/win32/misc/cron.h | 65 +++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 pandora_agents/win32/misc/cron.cc create mode 100644 pandora_agents/win32/misc/cron.h diff --git a/pandora_agents/win32/Makefile.am b/pandora_agents/win32/Makefile.am index d41c722ced..4641081570 100644 --- a/pandora_agents/win32/Makefile.am +++ b/pandora_agents/win32/Makefile.am @@ -1,9 +1,9 @@ bin_PROGRAMS = PandoraAgent if DEBUG -PandoraAgent_SOURCES = misc/pandora_file.cc modules/pandora_data.cc modules/pandora_module_factory.cc modules/pandora_module.cc modules/pandora_module_list.cc modules/pandora_module_plugin.cc modules/pandora_module_inventory.cc modules/pandora_module_freememory.cc modules/pandora_module_exec.cc modules/pandora_module_perfcounter.cc modules/pandora_module_proc.cc modules/pandora_module_tcpcheck.cc modules/pandora_module_freememory_percent.cc modules/pandora_module_freedisk.cc modules/pandora_module_freedisk_percent.cc modules/pandora_module_logevent.cc modules/pandora_module_service.cc modules/pandora_module_cpuusage.cc modules/pandora_module_wmiquery.cc modules/pandora_module_regexp.cc modules/pandora_module_ping.cc modules/pandora_module_snmpget.cc udp_server/udp_server.cc main.cc pandora_strutils.cc pandora.cc windows_service.cc pandora_agent_conf.cc windows/pandora_windows_info.cc windows/pandora_wmi.cc pandora_windows_service.cc misc/md5.c misc/sha256.cc windows/wmi/disphelper.c ssh/libssh2/channel.c ssh/libssh2/mac.c ssh/libssh2/session.c ssh/libssh2/comp.c ssh/libssh2/misc.c ssh/libssh2/sftp.c ssh/libssh2/crypt.c ssh/libssh2/packet.c ssh/libssh2/userauth.c ssh/libssh2/hostkey.c ssh/libssh2/publickey.c ssh/libssh2/kex.c ssh/libssh2/scp.c ssh/pandora_ssh_client.cc ssh/pandora_ssh_test.cc ftp/pandora_ftp_client.cc ftp/pandora_ftp_test.cc debug_new.cpp +PandoraAgent_SOURCES = misc/cron.cc misc/pandora_file.cc modules/pandora_data.cc modules/pandora_module_factory.cc modules/pandora_module.cc modules/pandora_module_list.cc modules/pandora_module_plugin.cc modules/pandora_module_inventory.cc modules/pandora_module_freememory.cc modules/pandora_module_exec.cc modules/pandora_module_perfcounter.cc modules/pandora_module_proc.cc modules/pandora_module_tcpcheck.cc modules/pandora_module_freememory_percent.cc modules/pandora_module_freedisk.cc modules/pandora_module_freedisk_percent.cc modules/pandora_module_logevent.cc modules/pandora_module_service.cc modules/pandora_module_cpuusage.cc modules/pandora_module_wmiquery.cc modules/pandora_module_regexp.cc modules/pandora_module_ping.cc modules/pandora_module_snmpget.cc udp_server/udp_server.cc main.cc pandora_strutils.cc pandora.cc windows_service.cc pandora_agent_conf.cc windows/pandora_windows_info.cc windows/pandora_wmi.cc pandora_windows_service.cc misc/md5.c misc/sha256.cc windows/wmi/disphelper.c ssh/libssh2/channel.c ssh/libssh2/mac.c ssh/libssh2/session.c ssh/libssh2/comp.c ssh/libssh2/misc.c ssh/libssh2/sftp.c ssh/libssh2/crypt.c ssh/libssh2/packet.c ssh/libssh2/userauth.c ssh/libssh2/hostkey.c ssh/libssh2/publickey.c ssh/libssh2/kex.c ssh/libssh2/scp.c ssh/pandora_ssh_client.cc ssh/pandora_ssh_test.cc ftp/pandora_ftp_client.cc ftp/pandora_ftp_test.cc debug_new.cpp PandoraAgent_CXXFLAGS=-g -O0 else -PandoraAgent_SOURCES = misc/pandora_file.cc modules/pandora_data.cc modules/pandora_module_factory.cc modules/pandora_module.cc modules/pandora_module_list.cc modules/pandora_module_plugin.cc modules/pandora_module_inventory.cc modules/pandora_module_freememory.cc modules/pandora_module_exec.cc modules/pandora_module_perfcounter.cc modules/pandora_module_proc.cc modules/pandora_module_tcpcheck.cc modules/pandora_module_freememory_percent.cc modules/pandora_module_freedisk.cc modules/pandora_module_freedisk_percent.cc modules/pandora_module_logevent.cc modules/pandora_module_logchannel.cc modules/pandora_module_service.cc modules/pandora_module_cpuusage.cc modules/pandora_module_wmiquery.cc modules/pandora_module_regexp.cc modules/pandora_module_ping.cc modules/pandora_module_snmpget.cc udp_server/udp_server.cc main.cc pandora_strutils.cc pandora.cc windows_service.cc pandora_agent_conf.cc windows/pandora_windows_info.cc windows/pandora_wmi.cc pandora_windows_service.cc misc/md5.c misc/sha256.cc windows/wmi/disphelper.c ssh/libssh2/channel.c ssh/libssh2/mac.c ssh/libssh2/session.c ssh/libssh2/comp.c ssh/libssh2/misc.c ssh/libssh2/sftp.c ssh/libssh2/crypt.c ssh/libssh2/packet.c ssh/libssh2/userauth.c ssh/libssh2/hostkey.c ssh/libssh2/publickey.c ssh/libssh2/kex.c ssh/libssh2/scp.c ssh/pandora_ssh_client.cc ssh/pandora_ssh_test.cc ftp/pandora_ftp_client.cc ftp/pandora_ftp_test.cc +PandoraAgent_SOURCES = misc/cron.cc misc/pandora_file.cc modules/pandora_data.cc modules/pandora_module_factory.cc modules/pandora_module.cc modules/pandora_module_list.cc modules/pandora_module_plugin.cc modules/pandora_module_inventory.cc modules/pandora_module_freememory.cc modules/pandora_module_exec.cc modules/pandora_module_perfcounter.cc modules/pandora_module_proc.cc modules/pandora_module_tcpcheck.cc modules/pandora_module_freememory_percent.cc modules/pandora_module_freedisk.cc modules/pandora_module_freedisk_percent.cc modules/pandora_module_logevent.cc modules/pandora_module_logchannel.cc modules/pandora_module_service.cc modules/pandora_module_cpuusage.cc modules/pandora_module_wmiquery.cc modules/pandora_module_regexp.cc modules/pandora_module_ping.cc modules/pandora_module_snmpget.cc udp_server/udp_server.cc main.cc pandora_strutils.cc pandora.cc windows_service.cc pandora_agent_conf.cc windows/pandora_windows_info.cc windows/pandora_wmi.cc pandora_windows_service.cc misc/md5.c misc/sha256.cc windows/wmi/disphelper.c ssh/libssh2/channel.c ssh/libssh2/mac.c ssh/libssh2/session.c ssh/libssh2/comp.c ssh/libssh2/misc.c ssh/libssh2/sftp.c ssh/libssh2/crypt.c ssh/libssh2/packet.c ssh/libssh2/userauth.c ssh/libssh2/hostkey.c ssh/libssh2/publickey.c ssh/libssh2/kex.c ssh/libssh2/scp.c ssh/pandora_ssh_client.cc ssh/pandora_ssh_test.cc ftp/pandora_ftp_client.cc ftp/pandora_ftp_test.cc PandoraAgent_CXXFLAGS=-O2 endif diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc new file mode 100644 index 0000000000..f49949effa --- /dev/null +++ b/pandora_agents/win32/misc/cron.cc @@ -0,0 +1,73 @@ +/* Pandora cron manager for Win32. + + Copyright (C) 2018 Artica ST. + Written by Fermin Hernandez. + + 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 2, 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include +#include +#include "cron.h" +#include "../pandora.h" + +/** + * @brief Constructor of cron class + * + * @param cron_string String with cron format (https://en.wikipedia.org/wiki/Cron) + */ +Cron::Cron (string cron_string) { + char cron_params[5][256], bottom[256], top[256]; + + // Parse the cron string + if (sscanf (cron_string.c_str (), "%255s %255s %255s %255s %255s", cron_params[0], cron_params[1], cron_params[2], cron_params[3], cron_params[4]) != 5) { + Pandora::pandoraDebug ("Invalid cron string: %s", cron_string.c_str ()); + this->isSet = false; + this->cronString = CRON_DEFAULT_STRING; + return; + } + + this->cronString = cron_string; + + // Check if cron string is the default + if (cron_string.compare(CRON_DEFAULT_STRING) == 0) { + this->isSet = false; + return; + } + + // Fill the cron structure + this->utimestamp = 0; + this->isSet = true; + // Months in cron are from 1 to 12. For date, are required from 0 to 11. + for (int i = 0; i < 5; i++) { + + // Wildcard + if (cron_params[i][0] == '*') { + this->params[i][0] = -1; + this->params[i][1] = -1; + + // Interval + } else if (sscanf (cron_params[i], "%255[^-]-%255s", bottom, top) == 2) { + this->params[i][0] = (i != 2) ? atoi (bottom) : atoi (bottom) - 1; + this->params[i][1] = (i != 2) ? atoi (top) : atoi (top) -1; + + // Single value + } else { + this->params[i][0] = (i != 2) + ? atoi (cron_params[i]) + : atoi (cron_params[i]) - 1; + this->params[i][1] = -1; + } + } +} diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h new file mode 100644 index 0000000000..1640ff34d0 --- /dev/null +++ b/pandora_agents/win32/misc/cron.h @@ -0,0 +1,65 @@ +/* Pandora cron manager for Win32. + + Copyright (C) 2016 Artica ST. + Written by Ramon Novoa. + + 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 2, 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, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef _CRON_PANDORA_H_ +#define _CRON_PANDORA_H_ + +#include +#include +#include +#include + +using namespace std; + +const string CRON_DEFAULT_STRING = "* * * * *"; + +class Cron { + private: + // Properties + time_t utimestamp; + /** + * @brief Stored cron values array + * + * First index: minutes, hours, months, days, month + * Second index: bottom, top + * + * Wildcard (*): Bottom and top are -1 + * Single value: Bottom is set and top is -1 + * Interval: Bottom and top are set + */ + int params[5][2]; + bool isSet; + string cronString; + + // Methods + bool validDate(int cronDate[5]); + + public: + // Constructor + Cron(string cron_string); + // Getter & setters + string getCronString(); + time_t getNextExecution(); + + // Other methods + bool executeNow(); +}; + +#endif From b566ca29e3d293354de3b447202c65335b9a3769 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 13:55:55 +0100 Subject: [PATCH 04/15] [Windows Agent] Added cron function isInCron --- pandora_agents/win32/misc/cron.cc | 104 ++++++++++++++++++++++++++++-- pandora_agents/win32/misc/cron.h | 8 ++- 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index f49949effa..84a3c5b926 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -54,20 +54,112 @@ Cron::Cron (string cron_string) { // Wildcard if (cron_params[i][0] == '*') { - this->params[i][0] = -1; - this->params[i][1] = -1; + this->params[i][CRDOWN] = CR_WILDCARD_VALUE; + this->params[i][1] = CR_WILDCARD_VALUE; // Interval } else if (sscanf (cron_params[i], "%255[^-]-%255s", bottom, top) == 2) { - this->params[i][0] = (i != 2) ? atoi (bottom) : atoi (bottom) - 1; - this->params[i][1] = (i != 2) ? atoi (top) : atoi (top) -1; + // Check if there is an interval with two equal values + if (strcmp(bottom, top) == 0) { + this->params[i][CRDOWN] = (i != 3) + ? atoi (cron_params[i]) + : atoi (cron_params[i]) - 1; + this->params[i][CRUP] = CR_WILDCARD_VALUE; + } else { + this->params[i][CRDOWN] = (i != 3) ? atoi (bottom) : atoi (bottom) - 1; + this->params[i][CRUP] = (i != 3) ? atoi (top) : atoi (top) -1; + } // Single value } else { - this->params[i][0] = (i != 2) + this->params[i][CRDOWN] = (i != 3) ? atoi (cron_params[i]) : atoi (cron_params[i]) - 1; - this->params[i][1] = -1; + this->params[i][CRUP] = CR_WILDCARD_VALUE; } } } +/** + * @brief Given a date, return if is inside a cron string or not + * + * @param date Date to check + * @return true If is inside cron + * @return false If is outside cron + */ +bool Cron::isInCron(time_t date) { + struct tm * timeinfo = localtime(&date); + + // Convert the tm struct to an array + int date_array[4] = { + timeinfo->tm_min, + timeinfo->tm_hour, + timeinfo->tm_mday, + timeinfo->tm_mon + }; + + // Check all positions faliures + for (int i = 0; i < 4; i++) { + if (!isWildCard(i)) { + if (isSingleValue(i)) { + if (this->params[i][CRDOWN] != date_array[i]) return false; + } else { + if (isNormalInterval(i)) { + if ( + date_array[i] < this->params[i][CRDOWN] || + date_array[i] > this->params[i][CRUP] + ) { + return false; + } + } else { + if ( + date_array[i] < this->params[i][CRDOWN] && + date_array[i] > this->params[i][CRUP] + ) { + return false; + } + } + } + } + } + + // If no failures, date is inside cron. + return true; +} + +/** + * @brief Check if a cron position is a wildcard + * + * @param position Position inside the param array + * @return true if is a wildcard + */ +bool Cron::isWildCard(int position) { + return this->params[position][CRDOWN] == CR_WILDCARD_VALUE; +} + +/** + * @brief Check if a cron position is a single value + * + * @param position Position inside the param array + * @return true if is a single value + */ +bool Cron::isSingleValue(int position) { + return this->params[position][CRUP] == CR_WILDCARD_VALUE; +} + +/** + * @brief Check if a cron position is an interval with down lower than up + * + * @param position Position inside the param array + * @return true if is a normal interval + * @return false if is an inverse interval + */ +bool Cron::isNormalInterval (int position) { + // Wildcard and single value will be treated like normal interval + if ( + this->params[position][CRDOWN] == CR_WILDCARD_VALUE || + this->params[position][CRUP] == CR_WILDCARD_VALUE + ) { + return true; + } + return (this->params[position][CRUP] >= this->params[position][CRDOWN]); +} \ No newline at end of file diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index 1640ff34d0..86b5906189 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -29,6 +29,9 @@ using namespace std; const string CRON_DEFAULT_STRING = "* * * * *"; +const int CR_WILDCARD_VALUE = -1; +const int CRDOWN = 0; +const int CRUP = 1; class Cron { private: @@ -49,7 +52,10 @@ class Cron { string cronString; // Methods - bool validDate(int cronDate[5]); + bool isInCron(time_t date); + bool isWildCard(int position); + bool isSingleValue(int position); + bool isNormalInterval(int position); public: // Constructor From 0446cdd8201ad6897a4b85fe13bd2c46664a046a Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 15:49:06 +0100 Subject: [PATCH 05/15] [Windows Agent] Remove old cron management --- pandora_agents/win32/misc/cron.cc | 34 ++++ pandora_agents/win32/misc/cron.h | 4 +- .../win32/modules/pandora_module.cc | 150 ++---------------- pandora_agents/win32/modules/pandora_module.h | 12 +- 4 files changed, 49 insertions(+), 151 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 84a3c5b926..676ce58320 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -79,6 +79,13 @@ Cron::Cron (string cron_string) { } } } + +/** + * @brief Getter of isSet property + * + */ +bool Cron::getIsSet () { return this->isSet; } + /** * @brief Given a date, return if is inside a cron string or not * @@ -162,4 +169,31 @@ bool Cron::isNormalInterval (int position) { return true; } return (this->params[position][CRUP] >= this->params[position][CRDOWN]); +} + +/** + * @brief Check if cron module should be executed at a given time + * + * @param date + * @return true if should execute + * @return false if should not execute + */ +bool Cron::shouldExecuteAt (time_t date) { + return this->utimestamp < date; +} + +/** + * @brief Update the cron utimestamp + * + * @param date Timestamp "from" to update cron utimestamp + * @param interval Module interval + */ +void Cron::update (time_t date, int interval) { + // TODO + this->utimestamp = date + interval; + Pandora::pandoraDebug( + "Module with cron %s will be executed at timestamp: %d.", + this->cronString.c_str(), + this->utimestamp + ); } \ No newline at end of file diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index 86b5906189..574ae9c791 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -61,11 +61,13 @@ class Cron { // Constructor Cron(string cron_string); // Getter & setters + bool getIsSet(); string getCronString(); time_t getNextExecution(); // Other methods - bool executeNow(); + void update(time_t date, int interval); + bool shouldExecuteAt(time_t date); }; #endif diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index 99b0d47f88..3b7e57df03 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -1563,158 +1563,28 @@ Pandora_Module::evaluateIntensiveConditions () { /** * Checks the module cron. Returns 1 if the module should run, 0 if not. * - * @return 1 if the module should run, 0 if not. + * @return true if the module should run. */ -int -Pandora_Module::checkCron (int module_interval, int agent_interval) { - int i, time_params[5]; - time_t current_time, offset; - struct tm *time_struct; - Cron *cron = this->cron; +bool +Pandora_Module::checkCron (int interval) { - // No cron - if (cron == NULL) { - return 1; - } + // Execute always if cron is not configured + if (!this->cron->getIsSet()) return true; - // Get current time - current_time = time (NULL); + time_t now = time(NULL); + if (!this->cron->shouldExecuteAt(now)) return false; - // Check if the module was already executed - if (current_time <= cron->utimestamp) { - return 0; - } + this->cron->update(now, interval); - // Break current time - time_struct = localtime(¤t_time); - if (time_struct == NULL) { - return 1; - } - - time_params[0] = time_struct->tm_min; - time_params[1] = time_struct->tm_hour; - time_params[2] = time_struct->tm_mday; - time_params[3] = time_struct->tm_mon; - time_params[4] = time_struct->tm_wday; - - // Fix month (localtime retuns 0..11 and we need 1..12) - time_params[3] += 1; - - // Check cron parameters - for (i = 0; i < 5; i++) { - - // Wildcard - if (cron->params[i][0] < 0) { - continue; - } - - // Check if next execution will overflow the cron (only minutes overflow) - // If overflow, execute the module - bool overflow_cron = false; - if (i == 0) { - int start_cron_seconds = cron->params[i][0]*60; - int current_exec_seconds = time_params[i]*60; - int next_exec_seconds = time_params[i]*60 + module_interval*agent_interval; - if (current_exec_seconds > start_cron_seconds && current_exec_seconds > next_exec_seconds) { - start_cron_seconds += 3600; - } - if ((current_exec_seconds <= start_cron_seconds) && (start_cron_seconds <= next_exec_seconds)) { - overflow_cron = true; - } - } - - // Check interval - if (cron->params[i][0] <= cron->params[i][1]) { - if ((time_params[i] < cron->params[i][0] || time_params[i] > cron->params[i][1]) && !overflow_cron) { - return 0; - } - } else { - if ((time_params[i] < cron->params[i][0] && time_params[i] > cron->params[i][1]) && !overflow_cron) { - return 0; - } - } - } - - // Do not check in the next minute, hour, day or month. - offset = 0; - if (cron->interval >= 0) { - offset = cron->interval; - } else if(cron->params[0][0] >= 0) { - // 1 minute - offset = 60; - } else if(cron->params[1][0] >= 0) { - // 1 hour - offset = 3600; - } else if(cron->params[2][0] >=0 || cron->params[4][0] >= 0) { - // 1 day - offset = 86400; - } else if(cron->params[3][0] >= 0) { - // 31 days - offset = 2678400; - } - - cron->utimestamp = current_time + offset; - return 1; + return true; } /** * Sets the module cron from a string. - * - * @return 1 if the module should run, 0 if not. */ void Pandora_Module::setCron (string cron_string) { - int i, value; - char cron_params[5][256], bottom[256], top[256]; - - /* Create the new cron if necessary */ - if (this->cron == NULL) { - this->cron = new Cron (); - } - - /* Parse the cron string */ - if (sscanf (cron_string.c_str (), "%255s %255s %255s %255s %255s", cron_params[0], cron_params[1], cron_params[2], cron_params[3], cron_params[4]) != 5) { - pandoraDebug ("Invalid cron string: %s", cron_string.c_str ()); - return; - } - - /* Fill the cron structure */ - this->cron->utimestamp = 0; - this->cron->interval = -1; - for (i = 0; i < 5; i++) { - - /* Wildcard */ - if (cron_params[i][0] == '*') { - this->cron->params[i][0] = -1; - - /* Interval */ - } else if (sscanf (cron_params[i], "%255[^-]-%255s", bottom, top) == 2) { - value = atoi (bottom); - this->cron->params[i][0] = value; - value = atoi (top); - this->cron->params[i][1] = value; - - /* Single value */ - } else { - value = atoi (cron_params[i]); - this->cron->params[i][0] = value; - this->cron->params[i][1] = value; - } - } -} - -/** - * Sets the interval of the module cron. - * - * @param interval Module cron interval in seconds. - */ -void -Pandora_Module::setCronInterval (int interval) { - if (this->cron == NULL) { - this->cron = new Cron (); - } - - this->cron->interval = interval; + this->cron = new Cron(cron_string); } /** diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index 2fbeb52e41..7d378bb6dd 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -22,6 +22,7 @@ #define __PANDORA_MODULE_H__ #include "../pandora.h" +#include "../misc/cron.h" #include "pandora_data.h" #include "boost/regex.h" #include @@ -108,15 +109,6 @@ namespace Pandora_Modules { regex_t regexp; } Condition; - /** - * Defines the structure that holds the module cron. - */ - typedef struct { - time_t utimestamp; - int interval; - int params[5][2]; - } Cron; - const string module_exec_str = "module_exec"; const string module_proc_str = "module_proc"; const string module_service_str = "module_service"; @@ -298,7 +290,7 @@ namespace Pandora_Modules { void addIntensiveCondition (string intensivecondition); int evaluatePreconditions (); void evaluateConditions (); - int checkCron (int module_interval, int agent_interval); + bool checkCron (int interval); void setCron (string cron_string); void setCronInterval (int interval); int evaluateCondition (string string_value, double double_value, Condition *condition); From f8f322e3287531740e190ccdab1ed089c36e7166 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 15:57:46 +0100 Subject: [PATCH 06/15] [Windows Agent] Removed all references to module_cron_interval --- pandora_agents/win32/modules/pandora_module.h | 1 - .../win32/modules/pandora_module_factory.cc | 19 +------------------ .../win32/pandora_windows_service.cc | 8 ++++---- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index 7d378bb6dd..9fb29e1183 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -292,7 +292,6 @@ namespace Pandora_Modules { void evaluateConditions (); bool checkCron (int interval); void setCron (string cron_string); - void setCronInterval (int interval); int evaluateCondition (string string_value, double double_value, Condition *condition); int evaluateIntensiveConditions (); int hasOutput (); diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 90c82d5457..308d5bb703 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -94,7 +94,6 @@ using namespace Pandora_Strutils; #define TOKEN_SAVE ("module_save ") #define TOKEN_CONDITION ("module_condition ") #define TOKEN_CRONTAB ("module_crontab ") -#define TOKEN_CRONINTERVAL ("module_cron_interval ") #define TOKEN_PRECONDITION ("module_precondition ") #define TOKEN_NOSEEKEOF ("module_noseekeof ") #define TOKEN_PING ("module_ping ") @@ -168,7 +167,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { string module_perfcounter, module_tcpcheck; string module_port, module_timeout, module_regexp; string module_plugin, module_save, module_condition, module_precondition; - string module_crontab, module_cron_interval, module_post_process; + string module_crontab, module_post_process; string module_min_critical, module_max_critical, module_min_warning, module_max_warning; string module_disabled, module_min_ff_event, module_noseekeof; string module_ping, module_ping_count, module_ping_timeout; @@ -222,7 +221,6 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_save = ""; module_condition = ""; module_crontab = ""; - module_cron_interval = ""; module_post_process = ""; module_precondition = ""; module_min_critical = ""; @@ -423,9 +421,6 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_crontab == "") { module_crontab = parseLine (line, TOKEN_CRONTAB); } - if (module_cron_interval == "") { - module_cron_interval = parseLine (line, TOKEN_CRONINTERVAL); - } if (module_noseekeof == "") { module_noseekeof = parseLine (line, TOKEN_NOSEEKEOF); } @@ -904,13 +899,6 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } } - if (module_cron_interval != "") { - pos_macro = module_cron_interval.find(macro_name); - if (pos_macro != string::npos){ - module_cron_interval.replace(pos_macro, macro_name.size(), macro_value); - } - } - if (module_noseekeof != "") { pos_macro = module_noseekeof.find(macro_name); if (pos_macro != string::npos){ @@ -1321,11 +1309,6 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { /* Module cron */ if (module_crontab != "") { module->setCron (module_crontab); - - /* Set the cron interval */ - if (module_cron_interval != "") { - module->setCronInterval (atoi (module_cron_interval.c_str ())); - } } /* Plugins do not have a module type */ diff --git a/pandora_agents/win32/pandora_windows_service.cc b/pandora_agents/win32/pandora_windows_service.cc index cad177411a..1abe51491a 100644 --- a/pandora_agents/win32/pandora_windows_service.cc +++ b/pandora_agents/win32/pandora_windows_service.cc @@ -1884,8 +1884,8 @@ Pandora_Windows_Service::pandora_run_broker (string config) { continue; } - /* Check preconditions */ - if (module->checkCron (module->getInterval (), atoi (conf->getValue ("interval").c_str())) == 0) { + /* Check cron */ + if (!module->checkCron (module->getInterval () * atoi (conf->getValue ("interval").c_str()))) { pandoraDebug ("Cron not matched for module %s", module->getName ().c_str ()); module->setNoOutput (); this->broker_modules->goNext (); @@ -2012,8 +2012,8 @@ Pandora_Windows_Service::pandora_run (int forced_run) { continue; } - /* Check preconditions */ - if (module->checkCron (module->getInterval (), atoi (conf->getValue ("interval").c_str())) == 0) { + /* Check cron */ + if (!module->checkCron (module->getInterval () * atoi (conf->getValue ("interval").c_str()))) { pandoraDebug ("Cron not matched for module %s", module->getName ().c_str ()); module->setNoOutput (); this->modules->goNext (); From 761a750ab7cf0e2ca42000e3d8a011057a6c856f Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 17:30:18 +0100 Subject: [PATCH 07/15] [Linux Agent] Added some comments on cron functions --- pandora_agents/unix/pandora_agent | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 32a66facea..e77bed96dc 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -2213,7 +2213,7 @@ sub cron_next_execution_date { my ($mday_down, undef) = cron_get_interval ($mday); $nex_time_array[2] = ($mday_down eq '*') ? 1 : $mday_down; - # When an overflow is passed check the hour update in the next execution + # When an overflow is passed check the day update in the next execution $nex_time = cron_valid_date(@nex_time_array, $cur_year); if ($nex_time >= $cur_time) { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); @@ -2236,12 +2236,13 @@ sub cron_next_execution_date { my ($mon_down, undef) = cron_get_interval ($mon); $nex_time_array[3] = ($mon_down eq '*') ? 0 : $mon_down; - # When an overflow is passed check the hour update in the next execution + # When an overflow is passed check the month update in the next execution $nex_time = cron_valid_date(@nex_time_array, $cur_year); if ($nex_time >= $cur_time) { return $nex_time if cron_is_in_cron(\@cron_array, \@nex_time_array); } + #Update the year if fails $nex_time = cron_valid_date(@nex_time_array, $cur_year + 1); return $nex_time; From ead21b75487a972d9223ce52cbba3f7ea5c916ae Mon Sep 17 00:00:00 2001 From: fermin831 Date: Wed, 21 Feb 2018 17:31:31 +0100 Subject: [PATCH 08/15] [Windows Agent] Added update cron function --- pandora_agents/win32/misc/cron.cc | 161 ++++++++++++++++++++++++++++-- pandora_agents/win32/misc/cron.h | 3 + 2 files changed, 157 insertions(+), 7 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 676ce58320..46f02f8a34 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -86,6 +86,20 @@ Cron::Cron (string cron_string) { */ bool Cron::getIsSet () { return this->isSet; } +/** + * @brief Set utimestamp (private set) + * + * @param date + */ +void Cron::setUtimestamp(time_t date) { + this->utimestamp = date; + Pandora::pandoraDebug( + "Module with cron %s will be executed at timestamp: %d.", + this->cronString.c_str(), + this->utimestamp + ); +} + /** * @brief Given a date, return if is inside a cron string or not * @@ -171,6 +185,21 @@ bool Cron::isNormalInterval (int position) { return (this->params[position][CRUP] >= this->params[position][CRDOWN]); } +/** + * @brief Get the reset value on a cron position + * + * @param position + * @return int Reset value + */ +int Cron::getResetValue (int position) { + int default_value = 0; + // Days start in 1 + if (position == 2) default_value = 1; + return isWildCard(position) + ? default_value + : this->params[position][CRDOWN]; +} + /** * @brief Check if cron module should be executed at a given time * @@ -189,11 +218,129 @@ bool Cron::shouldExecuteAt (time_t date) { * @param interval Module interval */ void Cron::update (time_t date, int interval) { - // TODO - this->utimestamp = date + interval; - Pandora::pandoraDebug( - "Module with cron %s will be executed at timestamp: %d.", - this->cronString.c_str(), - this->utimestamp - ); + + time_t nex_time = date + interval; + if (isInCron(nex_time)) { + setUtimestamp(nex_time); + return; + } + + // Copy tm struct values to an empty struct to avoid conflicts + struct tm * timeinfo_first = localtime(&nex_time); + struct tm * timeinfo = new tm(); + timeinfo->tm_sec = 0; + timeinfo->tm_min = timeinfo_first->tm_min; + timeinfo->tm_hour = timeinfo_first->tm_hour; + timeinfo->tm_mday = timeinfo_first->tm_mday; + timeinfo->tm_mon = timeinfo_first->tm_mon; + timeinfo->tm_year = timeinfo_first->tm_year; + + // Update minutes + timeinfo->tm_min = getResetValue(0); + nex_time = mktime(timeinfo); + if (nex_time >= date && isInCron(nex_time)) { + setUtimestamp(nex_time); + return; + } + + + printf("010: minutes\n"); + + if (nex_time == CRINVALID_DATE) { + // Update the month day if overflow + timeinfo->tm_hour = 0; + timeinfo->tm_mday++; + nex_time = mktime(timeinfo); + if (nex_time == CRINVALID_DATE) { + // Update the month if overflow + timeinfo->tm_mday = 1; + timeinfo->tm_mon++; + nex_time = mktime(timeinfo); + if (nex_time == CRINVALID_DATE) { + // Update the year if overflow + timeinfo->tm_mon = 0; + timeinfo->tm_year++; + nex_time = mktime(timeinfo); + } + } + } + + // Check the hour + if (isInCron(nex_time)) { + setUtimestamp(nex_time); + } + + // Update hour if fails + timeinfo->tm_hour = getResetValue(1); + + // When an overflow is passed check the hour update again + nex_time = mktime(timeinfo); + if (nex_time >= date && isInCron(nex_time)) { + setUtimestamp(nex_time); + return; + } + + // Check if next day is in cron + timeinfo->tm_mday++; + nex_time = mktime(timeinfo); + if (nex_time == CRINVALID_DATE) { + // Update the month if overflow + timeinfo->tm_mday = 1; + timeinfo->tm_mon++; + nex_time = mktime(timeinfo); + if (nex_time == CRINVALID_DATE) { + // Update the year if overflow + timeinfo->tm_mon = 0; + timeinfo->tm_year++; + nex_time = mktime(timeinfo); + } + } + + // Check the day + if (isInCron(nex_time)){ + setUtimestamp(nex_time); + return; + } + + // Update the day if fails + timeinfo->tm_mday = getResetValue(2); + + // When an overflow is passed check the day update in the next execution + nex_time = mktime(timeinfo); + if (nex_time >= date && isInCron(nex_time)) { + setUtimestamp(nex_time); + return; + } + + // Check if next month is in cron + timeinfo->tm_mon++; + nex_time = mktime(timeinfo); + if (nex_time == CRINVALID_DATE) { + // Update the year if overflow + timeinfo->tm_mon = 0; + timeinfo->tm_year++; + nex_time = mktime(timeinfo); + } + + // Check the month + if (isInCron(nex_time)) { + setUtimestamp(nex_time); + return; + } + + // Update the month if fails + timeinfo->tm_mon = getResetValue(3); + + // When an overflow is passed check the month update in the next execution + nex_time = mktime(timeinfo); + if (nex_time >= date) { + setUtimestamp(nex_time); + return; + } + + // Update the year if fails + timeinfo->tm_year++; + nex_time = mktime(timeinfo); + + setUtimestamp(nex_time); } \ No newline at end of file diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index 574ae9c791..876abf010a 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -32,6 +32,7 @@ const string CRON_DEFAULT_STRING = "* * * * *"; const int CR_WILDCARD_VALUE = -1; const int CRDOWN = 0; const int CRUP = 1; +const int CRINVALID_DATE = -1; class Cron { private: @@ -52,10 +53,12 @@ class Cron { string cronString; // Methods + void setUtimestamp(time_t date); bool isInCron(time_t date); bool isWildCard(int position); bool isSingleValue(int position); bool isNormalInterval(int position); + int getResetValue(int position); public: // Constructor From d53e17e1185d6500e6c8545371269a6574779aa0 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 09:26:23 +0100 Subject: [PATCH 09/15] [Windows Agent] Added cron_interval to XML --- pandora_agents/win32/misc/cron.cc | 43 ++++++++++++++----- pandora_agents/win32/misc/cron.h | 5 ++- .../win32/modules/pandora_module.cc | 10 +++-- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 46f02f8a34..b51c6cab11 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -19,6 +19,7 @@ */ #include #include +#include #include "cron.h" #include "../pandora.h" @@ -48,6 +49,7 @@ Cron::Cron (string cron_string) { // Fill the cron structure this->utimestamp = 0; + this->cronInterval = 0; this->isSet = true; // Months in cron are from 1 to 12. For date, are required from 0 to 11. for (int i = 0; i < 5; i++) { @@ -86,13 +88,32 @@ Cron::Cron (string cron_string) { */ bool Cron::getIsSet () { return this->isSet; } +/** + * @brief Getter of cronString property + * + */ +string Cron::getCronString() { return this->cronString; } + +/** + * @brief Getter of cronInterval property casting in string + * + */ +string Cron::getCronIntervalStr() { + stringstream ss; + ss << this->cronInterval; + return ss.str(); +} + + /** * @brief Set utimestamp (private set) * - * @param date + * @param date when module will be executed next time + * @param now current timestamp. Required to update interval */ -void Cron::setUtimestamp(time_t date) { +void Cron::setUtimestamp(time_t date, time_t now) { this->utimestamp = date; + this->cronInterval = date - now; Pandora::pandoraDebug( "Module with cron %s will be executed at timestamp: %d.", this->cronString.c_str(), @@ -221,7 +242,7 @@ void Cron::update (time_t date, int interval) { time_t nex_time = date + interval; if (isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -239,7 +260,7 @@ void Cron::update (time_t date, int interval) { timeinfo->tm_min = getResetValue(0); nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -267,7 +288,7 @@ void Cron::update (time_t date, int interval) { // Check the hour if (isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); } // Update hour if fails @@ -276,7 +297,7 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the hour update again nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -298,7 +319,7 @@ void Cron::update (time_t date, int interval) { // Check the day if (isInCron(nex_time)){ - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -308,7 +329,7 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the day update in the next execution nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -324,7 +345,7 @@ void Cron::update (time_t date, int interval) { // Check the month if (isInCron(nex_time)) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -334,7 +355,7 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the month update in the next execution nex_time = mktime(timeinfo); if (nex_time >= date) { - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); return; } @@ -342,5 +363,5 @@ void Cron::update (time_t date, int interval) { timeinfo->tm_year++; nex_time = mktime(timeinfo); - setUtimestamp(nex_time); + setUtimestamp(nex_time, date); } \ No newline at end of file diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index 876abf010a..e27d81062b 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -51,9 +51,10 @@ class Cron { int params[5][2]; bool isSet; string cronString; + time_t cronInterval; // Methods - void setUtimestamp(time_t date); + void setUtimestamp(time_t date, time_t now); bool isInCron(time_t date); bool isWildCard(int position); bool isSingleValue(int position); @@ -66,7 +67,7 @@ class Cron { // Getter & setters bool getIsSet(); string getCronString(); - time_t getNextExecution(); + string getCronIntervalStr(); // Other methods void update(time_t date, int interval); diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index 3b7e57df03..57a2c26b15 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -740,10 +740,14 @@ Pandora_Module::getXml () { } /* Module Crontab */ - if (this->module_crontab != "") { + if (this->cron->getIsSet()) { module_xml += "\t"; - module_xml += this->module_crontab; + module_xml += this->cron->getCronString(); module_xml += "\n"; + + module_xml += "\tcron->getCronIntervalStr(); + module_xml += "]]>\n"; } /* Write module data */ @@ -1563,7 +1567,7 @@ Pandora_Module::evaluateIntensiveConditions () { /** * Checks the module cron. Returns 1 if the module should run, 0 if not. * - * @return true if the module should run. + * @return 1 if the module should run, 0 if not. */ bool Pandora_Module::checkCron (int interval) { From 611652820c3dd0d3c681e22e6cf696582fe64d19 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 09:30:12 +0100 Subject: [PATCH 10/15] [Windows Agent] Removed unwanted trace --- pandora_agents/win32/misc/cron.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index b51c6cab11..4db0e40094 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -264,9 +264,6 @@ void Cron::update (time_t date, int interval) { return; } - - printf("010: minutes\n"); - if (nex_time == CRINVALID_DATE) { // Update the month day if overflow timeinfo->tm_hour = 0; From 5a3e4e1599b76cc41d0520d67fca7b66831cfbbe Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 09:55:59 +0100 Subject: [PATCH 11/15] [Windows Agent] Avoid execute module at first time if is out cron --- pandora_agents/win32/misc/cron.cc | 16 ++++++++++++++++ pandora_agents/win32/misc/cron.h | 5 +++-- pandora_agents/win32/modules/pandora_module.cc | 5 ++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 4db0e40094..7a7e1da2f3 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -232,6 +232,22 @@ bool Cron::shouldExecuteAt (time_t date) { return this->utimestamp < date; } +/** + * @brief Check if a module should be executed when utimestamp is not calculated yet + * + * @param date Current date + * @return true It is not first time and current date fit in cron + * @return false Don't execute first time + */ +bool Cron::shouldExecuteAtFirst (time_t date) { + + // Return true if it is not first + if (this->utimestamp != 0) return true; + + // Check current date in cron + return isInCron(date); +} + /** * @brief Update the cron utimestamp * diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index e27d81062b..f1647b64cd 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -1,7 +1,7 @@ /* Pandora cron manager for Win32. - Copyright (C) 2016 Artica ST. - Written by Ramon Novoa. + Copyright (C) 2018 Artica ST. + Written by Fermin Hernandez. 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 @@ -72,6 +72,7 @@ class Cron { // Other methods void update(time_t date, int interval); bool shouldExecuteAt(time_t date); + bool shouldExecuteAtFirst(time_t date); }; #endif diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index 57a2c26b15..d7d5fb63c0 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -1578,9 +1578,12 @@ Pandora_Module::checkCron (int interval) { time_t now = time(NULL); if (!this->cron->shouldExecuteAt(now)) return false; + // Check if should execute this module at first before update cron params + bool execute = this->cron->shouldExecuteAtFirst(now); + this->cron->update(now, interval); - return true; + return execute; } /** From 0dc07b6285904664601fdc03d8d64bcb354bfda0 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 10:50:00 +0100 Subject: [PATCH 12/15] [Windows Agent] Refactorized update cron update function to permit day of week support --- pandora_agents/win32/misc/cron.cc | 43 +++++++++++++++++++------------ pandora_agents/win32/misc/cron.h | 1 + 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 7a7e1da2f3..523b0397fe 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -255,11 +255,28 @@ bool Cron::shouldExecuteAtFirst (time_t date) { * @param interval Module interval */ void Cron::update (time_t date, int interval) { + time_t next_time = getNextExecutionFrom(date, interval); + if (isWildCard(4)) { + setUtimestamp (next_time, date); + return; + } + // TODO if set day of the week + setUtimestamp (next_time, date); +} + +/** + * @brief Get next execution date given a certain date. + * + * @param date Date when start the search for a new date + * @param interval Module interval + * @return time_t Timestamp when module should be executed next time + * @remarks It does not look for day of the week + */ +time_t Cron::getNextExecutionFrom(time_t date, int interval) { time_t nex_time = date + interval; if (isInCron(nex_time)) { - setUtimestamp(nex_time, date); - return; + return nex_time; } // Copy tm struct values to an empty struct to avoid conflicts @@ -276,8 +293,7 @@ void Cron::update (time_t date, int interval) { timeinfo->tm_min = getResetValue(0); nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time, date); - return; + return nex_time; } if (nex_time == CRINVALID_DATE) { @@ -301,7 +317,7 @@ void Cron::update (time_t date, int interval) { // Check the hour if (isInCron(nex_time)) { - setUtimestamp(nex_time, date); + return nex_time; } // Update hour if fails @@ -310,8 +326,7 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the hour update again nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time, date); - return; + return nex_time; } // Check if next day is in cron @@ -332,8 +347,7 @@ void Cron::update (time_t date, int interval) { // Check the day if (isInCron(nex_time)){ - setUtimestamp(nex_time, date); - return; + return nex_time; } // Update the day if fails @@ -342,8 +356,7 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the day update in the next execution nex_time = mktime(timeinfo); if (nex_time >= date && isInCron(nex_time)) { - setUtimestamp(nex_time, date); - return; + return nex_time; } // Check if next month is in cron @@ -358,8 +371,7 @@ void Cron::update (time_t date, int interval) { // Check the month if (isInCron(nex_time)) { - setUtimestamp(nex_time, date); - return; + return nex_time; } // Update the month if fails @@ -368,13 +380,12 @@ void Cron::update (time_t date, int interval) { // When an overflow is passed check the month update in the next execution nex_time = mktime(timeinfo); if (nex_time >= date) { - setUtimestamp(nex_time, date); - return; + return nex_time; } // Update the year if fails timeinfo->tm_year++; nex_time = mktime(timeinfo); - setUtimestamp(nex_time, date); + return nex_time; } \ No newline at end of file diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index f1647b64cd..992598fb7e 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -55,6 +55,7 @@ class Cron { // Methods void setUtimestamp(time_t date, time_t now); + time_t getNextExecutionFrom(time_t date, int interval); bool isInCron(time_t date); bool isWildCard(int position); bool isSingleValue(int position); From bea95b03148c813a3e33fc356caff6f7cc71c691 Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 12:08:47 +0100 Subject: [PATCH 13/15] [Windows Agent] Added support for cron day of the week --- pandora_agents/win32/misc/cron.cc | 102 ++++++++++++++++++------------ pandora_agents/win32/misc/cron.h | 4 +- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index 523b0397fe..b1e70c9d88 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -104,23 +104,6 @@ string Cron::getCronIntervalStr() { return ss.str(); } - -/** - * @brief Set utimestamp (private set) - * - * @param date when module will be executed next time - * @param now current timestamp. Required to update interval - */ -void Cron::setUtimestamp(time_t date, time_t now) { - this->utimestamp = date; - this->cronInterval = date - now; - Pandora::pandoraDebug( - "Module with cron %s will be executed at timestamp: %d.", - this->cronString.c_str(), - this->utimestamp - ); -} - /** * @brief Given a date, return if is inside a cron string or not * @@ -141,30 +124,42 @@ bool Cron::isInCron(time_t date) { // Check all positions faliures for (int i = 0; i < 4; i++) { - if (!isWildCard(i)) { - if (isSingleValue(i)) { - if (this->params[i][CRDOWN] != date_array[i]) return false; + if (!isBetweenParams(date_array[i], i)) return false; + } + + // If no failures, date is inside cron. + return true; +} + +/** + * @brief Check if a value is in a position of cron + * + * @param value Value to check + * @param position Position in cron to make the check + * @return If position is in cron + */ +bool Cron::isBetweenParams(int value, int position) { + if (!isWildCard(position)) { + if (isSingleValue(position)) { + if (this->params[position][CRDOWN] != value) return false; + } else { + if (isNormalInterval(position)) { + if ( + value < this->params[position][CRDOWN] || + value > this->params[position][CRUP] + ) { + return false; + } } else { - if (isNormalInterval(i)) { - if ( - date_array[i] < this->params[i][CRDOWN] || - date_array[i] > this->params[i][CRUP] - ) { - return false; - } - } else { - if ( - date_array[i] < this->params[i][CRDOWN] && - date_array[i] > this->params[i][CRUP] - ) { - return false; - } + if ( + value < this->params[position][CRDOWN] && + value > this->params[position][CRUP] + ) { + return false; } } } } - - // If no failures, date is inside cron. return true; } @@ -256,13 +251,38 @@ bool Cron::shouldExecuteAtFirst (time_t date) { */ void Cron::update (time_t date, int interval) { time_t next_time = getNextExecutionFrom(date, interval); - if (isWildCard(4)) { - setUtimestamp (next_time, date); - return; + + // Check the day of the week + struct tm * timeinfo = localtime(&next_time); + int count = 0; // Avoid infinite loops + while ((!isBetweenParams(timeinfo->tm_wday, 4)) && (count++ < CR_MAX_ITERS)){ + next_time = getNextExecutionFrom(next_time + CR_SECONDS_ONE_DAY, 0); + timeinfo = localtime(&next_time); + } + if (count >= CR_MAX_ITERS) { + Pandora::pandoraLog( + "Module with cron %s will be executed at timestamp: %d, but it can be incorrect", + this->cronString.c_str(), + this->utimestamp + ); } - // TODO if set day of the week - setUtimestamp (next_time, date); + // Security about values + if (next_time < date) { + this->utimestamp = date + interval; + this->cronInterval = interval; + Pandora::pandoraLog("Cron update fails in Module with cron %s", this->cronString.c_str()); + } + + // Save the data + this->utimestamp = next_time; + this->cronInterval = next_time - date; + Pandora::pandoraDebug( + "Module with cron %s will be executed at timestamp: %d.", + this->cronString.c_str(), + this->utimestamp + ); + return; } /** diff --git a/pandora_agents/win32/misc/cron.h b/pandora_agents/win32/misc/cron.h index 992598fb7e..022bf1bb41 100644 --- a/pandora_agents/win32/misc/cron.h +++ b/pandora_agents/win32/misc/cron.h @@ -33,6 +33,8 @@ const int CR_WILDCARD_VALUE = -1; const int CRDOWN = 0; const int CRUP = 1; const int CRINVALID_DATE = -1; +const int CR_SECONDS_ONE_DAY = 86400; +const int CR_MAX_ITERS = 60; class Cron { private: @@ -54,9 +56,9 @@ class Cron { time_t cronInterval; // Methods - void setUtimestamp(time_t date, time_t now); time_t getNextExecutionFrom(time_t date, int interval); bool isInCron(time_t date); + bool isBetweenParams(int value, int position); bool isWildCard(int position); bool isSingleValue(int position); bool isNormalInterval(int position); From 94c1ce304d8eda7c5f2847c2040f3bad22133d1c Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 12:39:26 +0100 Subject: [PATCH 14/15] Removed all module_cron_interval vestiges --- pandora_agents/pc/pandora_agent | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandora_agents/pc/pandora_agent b/pandora_agents/pc/pandora_agent index 080af0b8fa..b105a8c654 100644 --- a/pandora_agents/pc/pandora_agent +++ b/pandora_agents/pc/pandora_agent @@ -510,8 +510,6 @@ sub parse_conf_modules($) { } } elsif ($line =~ /^\s*module_crontab\s+(((\*|(\d+(-\d+){0,1}))\s*){5}).*$/) { $module->{'cron'} = $1; - } elsif ($line =~ /^\s*module_cron_interval\s+(\d+).*$/) { - $module->{'cron_interval'} = $1; } elsif ($line =~ /^\s*module_end\s*$/) { next unless ($module->{'name'} ne '') and ($module->{'func'} != 0); From 8e6e5480d2500aa19154e033a92d84e57da4e55c Mon Sep 17 00:00:00 2001 From: fermin831 Date: Thu, 22 Feb 2018 13:51:10 +0100 Subject: [PATCH 15/15] [Windows Agent] Fixed error on non cron configured modules --- pandora_agents/win32/misc/cron.cc | 17 ++++++++++------- .../win32/modules/pandora_module_factory.cc | 4 +--- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pandora_agents/win32/misc/cron.cc b/pandora_agents/win32/misc/cron.cc index b1e70c9d88..d712c2685c 100644 --- a/pandora_agents/win32/misc/cron.cc +++ b/pandora_agents/win32/misc/cron.cc @@ -30,7 +30,16 @@ */ Cron::Cron (string cron_string) { char cron_params[5][256], bottom[256], top[256]; - + + // Check if cron string is the default or empty + if ( + cron_string.compare(CRON_DEFAULT_STRING) == 0 || + cron_string.compare("") == 0 + ) { + this->isSet = false; + return; + } + // Parse the cron string if (sscanf (cron_string.c_str (), "%255s %255s %255s %255s %255s", cron_params[0], cron_params[1], cron_params[2], cron_params[3], cron_params[4]) != 5) { Pandora::pandoraDebug ("Invalid cron string: %s", cron_string.c_str ()); @@ -40,12 +49,6 @@ Cron::Cron (string cron_string) { } this->cronString = cron_string; - - // Check if cron string is the default - if (cron_string.compare(CRON_DEFAULT_STRING) == 0) { - this->isSet = false; - return; - } // Fill the cron structure this->utimestamp = 0; diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 308d5bb703..658ff724fd 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -1307,9 +1307,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { } /* Module cron */ - if (module_crontab != "") { - module->setCron (module_crontab); - } + module->setCron (module_crontab); /* Plugins do not have a module type */ if (module_plugin == "") {