diff --git a/pandora_console/godmode/wizards/HostDevices.class.php b/pandora_console/godmode/wizards/HostDevices.class.php index 5f6f0c7dba..c1d970086e 100755 --- a/pandora_console/godmode/wizards/HostDevices.class.php +++ b/pandora_console/godmode/wizards/HostDevices.class.php @@ -491,6 +491,7 @@ class HostDevices extends Wizard $parent_recursion = get_parameter_switch('parent_recursion'); $vlan_enabled = get_parameter_switch('vlan_enabled'); $wmi_enabled = get_parameter_switch('wmi_enabled'); + $rcmd_enabled = get_parameter_switch('rcmd_enabled'); $resolve_names = get_parameter_switch('resolve_names'); $snmp_version = get_parameter('snmp_version', null); $community = get_parameter('community', null); @@ -538,6 +539,7 @@ class HostDevices extends Wizard $this->task['parent_recursion'] = $parent_recursion; $this->task['vlan_enabled'] = $vlan_enabled; $this->task['wmi_enabled'] = $wmi_enabled; + $this->task['rcmd_enabled'] = $rcmd_enabled; $this->task['resolve_names'] = $resolve_names; $this->task['snmp_version'] = $snmp_version; $this->task['snmp_auth_user'] = $snmp_auth_user; diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm index 8cee68d538..7303771422 100644 --- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm +++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm @@ -276,6 +276,9 @@ sub data_consumer ($$) { task_id => $task->{'id_rt'}, vlan_cache_enabled => $task->{'vlan_enabled'}, wmi_enabled => $task->{'wmi_enabled'}, + rcmd_enabled => $task->{'rcmd_enabled'}, + rcmd_timeout => $pa_config->{'rcmd_timeout'}, + rcmd_timeout_bin => $pa_config->{'rcmd_timeout_bin'}, auth_strings_array => \@auth_strings, autoconfiguration_enabled => $task->{'autoconfiguration_enabled'}, main_event_id => $main_event, @@ -402,6 +405,8 @@ sub exec_recon_script ($$$) { sub PandoraFMS::Recon::Base::guess_os($$) { my ($self, $device) = @_; + return $self->{'os_id'}{$device} if defined($self->{'os_id'}{$device}); + $DEVNULL = '/dev/null' if (!defined($DEVNULL)); $DEVNULL = '/NUL' if ($^O =~ /win/i && !defined($DEVNULL)); @@ -510,6 +515,9 @@ sub PandoraFMS::Recon::Base::test_module($$) { ) { # Generic, plugins. (21-23 ASYNC) if ($test->{'id_modulo'} == 6) { + + return 0 unless $self->wmi_responds($addr); + # WMI commands. $value = $self->call( 'wmi_get_value', @@ -527,9 +535,31 @@ sub PandoraFMS::Recon::Base::test_module($$) { } elsif ($test->{'id_tipo_modulo'} >= 34 && $test->{'id_tipo_modulo'} <= 37) { # Remote command. - # XXX TODO: Test remote commands. - # Disabled until we can ensure result. - return 0; + return 0 unless $self->rcmd_responds($addr); + + my $target_os = pandora_get_os($self->{'dbh'}, $test->{'custom_string_2'}); + + $value = enterprise_hook( + 'remote_execution_module', + [ + # pa_config, + $self->{'pa_config'}, + # dbh, + $self->{'dbh'}, + # module, + $test, + # target_os, + $target_os, + # ip_target, + $test->{'ip_target'}, + # tcp_port + $test->{'tcp_port'} + ] + ); + + chomp($value); + + return 0 unless defined($value); } elsif ($test->{'id_tipo_modulo'} >= 8 && $test->{'id_tipo_modulo'} <= 11) { # TCP @@ -917,6 +947,15 @@ sub PandoraFMS::Recon::Base::create_network_profile_modules($$) { $component->{'plugin_pass'} = $self->{'snmp_auth_pass'}; } + if ($component->{'type'} >= 34 && $component->{'type'} <= 37) { + # Update module credentials. + $component->{'custom_string_1'} = $self->rcmd_credentials_key($device); + $component->{'custom_string_2'} = pandora_get_os_by_id( + $self->{'dbh'}, + $self->guess_os($device) + ); + } + $component->{'__module_component'} = 1; # 3. Try to register module into monitoring list. @@ -1012,7 +1051,10 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { || $force_creation ) { my $parent_id; - my $os_id = $self->guess_os($data->{'agent'}{'direccion'}); + my $os_id = $data->{'agent'}{'id_os'}; + if (is_empty($os_id)) { + $os_id = $self->guess_os($data->{'agent'}{'direccion'}); + } $self->call('message', "Agent accepted: ".$data->{'agent'}{'nombre'}, 5); @@ -1337,6 +1379,9 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { next if is_empty($label); + # Retrieve target agent OS version. + $self->{'agents_found'}->{$addr}{'agent'}{'id_os'} = $self->guess_os($addr); + $self->call('update_progress', $progress); $progress += $step; # Store temporally. Wait user approval. diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index 4b3a920f9f..dec92f1437 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -160,6 +160,12 @@ sub new { # Globally enable/disable WMI scans. wmi_enabled => 0, + + # Globally enable/disable RCMD scans. + rcmd_enabled => 0, + rcmd_timeout => 4, + rcmd_timeout_bin => '/usr/bin/timeout', + auth_strings_array => [], wmi_timeout => 3, timeout_cmd => '', @@ -1429,6 +1435,12 @@ sub test_capabilities($$) { # Add wmi scan if enabled. $self->wmi_discovery($addr); } + + # WMI discovery. + if (is_enabled($self->{'rcmd_enabled'})) { + # Add wmi scan if enabled. + $self->rcmd_discovery($addr); + } } ################################################################################ @@ -2268,6 +2280,105 @@ sub wmi_credentials_calculation { return undef; } +################################################################################ +# Returns the credentials with which the host responds to WMI queries or +# undef if it does not respond to WMI. +################################################################################ +sub rcmd_credentials { + my ($self, $target) = @_; + return $self->{'rcmd_auth'}{$target}; +} + +################################################################################ +# Returns the credentials KEY with which the host responds to WMI queries or +# undef if it does not respond to WMI. +################################################################################ +sub rcmd_credentials_key { + my ($self, $target) = @_; + return $self->{'rcmd_auth_key'}{$target}; +} + +################################################################################ +# Calculate WMI credentials for target, 1 if calculated, undef if cannot +# connect to target. Credentials could be empty (-N) +################################################################################ +sub rcmd_credentials_calculation { + my ($self, $target) = @_; + + my $rcmd = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::RemoteCmd',[{ + 'psexec' => $self->{'parent'}->{'pa_config'}->{'psexec'}, + 'winexe' => $self->{'parent'}->{'pa_config'}->{'winexe'}, + 'plink' => $self->{'parent'}->{'pa_config'}->{'plink'} + }] + ); + + if (!$rcmd) { + # Library not available. + $self->call('message', "PandoraFMS::RemoteCmd library not available", 10); + return undef; + } + + my $id_os = $self->call('guess_os', $target); + $rcmd->set_host($target); + $rcmd->set_os($id_os); + + # Test all credentials selected. + foreach my $key_index (@{$self->{'auth_strings_array'}}) { + my $cred = $self->call('get_credentials', $key_index); + next if ref($cred) ne 'HASH'; + $rcmd->clean_ssh_lib(); + + my $username; + my $domain; + + if($cred->{'username'} =~ /^(.*?)\\(.*)$/) { + $domain = $1; + $username = $2; + } else { + $username = $cred->{'username'}; + } + + $rcmd->set_credentials( + { + 'user' => $username, + 'pass' => $cred->{'password'}, + 'domain' => $domain + } + ); + + $rcmd->set_timeout( + $self->{'rcmd_timeout_bin'}, + $self->{'rcmd_timeout'} + ); + + my $result; + eval { + $result = $rcmd->rcmd('echo 1'); + chomp($result); + my $out = ''; + $out = $result if !is_empty($result); + $self->call('message', "Trying [".$key_index."] in [". $target."] [".$id_os."]: [$out]", 10); + }; + if ($@) { + $self->call('message', "Failed while trying [".$key_index."] in [". $target."] [".$id_os."]:" . @_, 10); + } + + if (!is_empty($result) && $result == "1") { + $self->{'rcmd_auth'}{$target} = $cred; + $self->{'rcmd_auth_key'}{$target} = $key_index; + $self->{'rcmd'}{$target} = 1; + $self->{'summary'}->{'RCMD'} += 1; + $self->call('message', "RCMD available for $target", 10); + return 1; + } + + } + + # Not found. + return 0; +} + ################################################################################ # Tests wmi capability for addr. ################################################################################ @@ -2282,6 +2393,20 @@ sub wmi_discovery { } +################################################################################ +# Tests credentials against addr. +################################################################################ +sub rcmd_discovery { + my ($self, $addr) = @_; + + # Initialization. + $self->{'rcmd'} = {} unless ref($self->{'rcmd'}) eq 'HASH'; + + # Calculate credentials. + $self->rcmd_credentials_calculation($addr); + +} + ################################################################################ # Extra: WMI imported methods. DO NOT EXPORT TO AVOID DOUBLE DEF. ################################################################################ @@ -2371,6 +2496,15 @@ sub wmi_responds { return 0; } +################################################################################ +# Checks if target is reachable using rcmd. +################################################################################ +sub rcmd_responds { + my ($self, $target) = @_; + return 1 if is_enabled($self->{'rcmd'}{$target}); + return 0; +} + ################################################################################ # Performs a WMI request and returns the requested column of the first row. # Returns undef on error.