WMI review Discovery

This commit is contained in:
fbsanchez 2020-03-26 13:44:08 +01:00
parent 2fb3d664cf
commit 3eadde8a87
2 changed files with 250 additions and 413 deletions

View File

@ -531,16 +531,14 @@ sub PandoraFMS::Recon::Base::test_module($$) {
return 0 if is_empty($value);
# 2. Check if value matches type definition and fits thresholds.
if (is_in_array([1,2,4,5,6,7,8,9,11,15,16,18,21,22,25,30,31,32,34,35,37],$test->{'id_tipo_modulo'})) {
if (is_in_array(
[1,2,4,5,6,7,8,9,11,15,16,18,21,22,25,30,31,32,34,35,37],
$test->{'id_tipo_modulo'}
)
) {
# Numeric.
return 0 unless is_numeric($value);
if (!is_enabled($test->{'critical_inverse'})) {
return 0 if $value >= $test->{'min_critical'} && $value <= $test->{'max_critical'};
} else {
return 0 if $value < $test->{'min_critical'} && $value > $test->{'max_critical'};
}
if (is_in_array([2,6,9,18,21,31,35], $test->{'id_tipo_modulo'})) {
# Boolean.
if (!is_enabled($test->{'critical_inverse'})) {
@ -550,6 +548,27 @@ sub PandoraFMS::Recon::Base::test_module($$) {
}
}
my $thresholds_defined = 0;
if ((!defined($test->{'min_critical'}) || $test->{'min_critical'} == 0)
&& (!defined($test->{'max_critical'}) || $test->{'max_critical'} == 0)
) {
# In Default 0,0 do not test.or not defined
$thresholds_defined = 0;
} else {
# min or max are diferent from 0
$thresholds_defined = 1;
}
if ($thresholds_defined > 0) {
# Check thresholds.
if (!is_enabled($test->{'critical_inverse'})) {
return 0 if $value >= $test->{'min_critical'} && $value <= $test->{'max_critical'};
} else {
return 0 if $value < $test->{'min_critical'} && $value > $test->{'max_critical'};
}
}
} else {
# String.
if (!is_enabled($test->{'critical_inverse'})) {
@ -729,6 +748,80 @@ sub PandoraFMS::Recon::Base::create_interface_modules($$) {
}
################################################################################
# Add wmi modules to the given host.
################################################################################
sub PandoraFMS::Recon::Base::create_wmi_modules {
my ($self, $target) = @_;
# Add modules to the agent if it responds to WMI.
return unless ($self->wmi_responds($target));
my $auth = $self->wmi_credentials($target);
# Register agent.
$self->add_agent($target);
# Add modules.
# CPU.
my @cpus = $self->wmi_get_value_array($target, 'SELECT DeviceId FROM Win32_Processor', 0);
foreach my $cpu (@cpus) {
$self->add_module(
$target,
{
'target' => $target,
'query' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'",
'auth' => $auth,
'column' => 1,
'name' => "CPU Load $cpu",
'description' => safe_input("Load for $cpu (%)"),
'id_tipo_modulo' => 1,
'id_modulo' => 6,
'unit' => '%',
}
);
}
# Memory.
my $mem = $self->wmi_get_value($target, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0);
if (defined($mem)) {
$self->add_module(
$target,
{
'target' => $target,
'query' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem",
'auth' => $auth,
'column' => 0,
'name' => 'FreeMemory',
'description' => safe_input('Free memory'),
'id_tipo_modulo' => 1,
'id_modulo' => 6,
'unit' => 'KB',
}
);
}
# Disk.
my @units = $self->wmi_get_value_array($target, 'SELECT DeviceID FROM Win32_LogicalDisk', 0);
foreach my $unit (@units) {
$self->add_module(
$target,
{
'target' => $target,
'query' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'",
'auth' => $auth,
'column' => 1,
'name' => "FreeDisk $unit",
'description' => safe_input('Available disk space in kilobytes'),
'id_tipo_modulo' => 1,
'id_modulo' => 6,
'unit' => 'KB',
}
);
}
}
################################################################################
# Create network profile modules for the given agent.
################################################################################
@ -797,6 +890,19 @@ sub PandoraFMS::Recon::Base::create_network_profile_modules($$) {
}
################################################################################
# Retrieve a key from credential store.
################################################################################
sub PandoraFMS::Recon::Base::get_credentials {
my ($self, $key_index) = @_;
return credential_store_get_key(
$self->{'pa_config'},
$self->{'dbh'},
$key_index
);
}
################################################################################
# Create agents and modules reported by Recon::Base.
################################################################################
@ -1183,6 +1289,9 @@ sub PandoraFMS::Recon::Base::apply_monitoring($) {
# Monitorization - interfaces
$self->call('create_interface_modules', $label);
# Monitorization - WMI modules.
$self->call('create_wmi_modules', $label);
}
$self->{'c_network_percent'} = 100;
@ -1358,319 +1467,6 @@ sub PandoraFMS::Recon::Base::create_agents($$) {
}
################################################################################
# Create an agent for the given device. Returns the ID of the new (or
# existing) agent, undef on error.
################################################################################
sub PandoraFMS::Recon::Base::create_agent($$) {
my ($self, $device) = @_;
# Clean name.
$device = clean_blank($device);
# Resolve hostnames.
my $host_name = (($self->{'resolve_names'} == 1) ? gethostbyaddr(inet_aton($device), AF_INET) : $device);
# Fallback to device IP if host name could not be resolved.
$host_name = $device if (!defined($host_name) || $host_name eq '');
my $agent = locate_agent($self->{'pa_config'}, $self->{'dbh'}, $host_name);
my ($agent_id, $agent_learning);
if (!defined($agent)) {
$host_name = $device unless defined ($host_name);
# Guess the OS.
my $id_os = $self->guess_os($device);
# Are we filtering hosts by OS?
return if ($self->{'id_os'} > 0 && $id_os != $self->{'id_os'});
# Are we filtering hosts by TCP port?
return if ($self->{'recon_ports'} ne '' && $self->tcp_scan($device) == 0);
my $location = get_geoip_info($self->{'pa_config'}, $device);
$agent_id = pandora_create_agent(
$self->{'pa_config'}, $self->{'pa_config'}->{'servername'},
$host_name, $device, $self->{'group_id'}, 0, $id_os,
'', 300, $self->{'dbh'}, undef, $location->{'longitude'},
$location->{'latitude'}
);
return undef unless defined ($agent_id) and ($agent_id > 0);
# Autoconfigure agent
if (defined($self->{'autoconfiguration_enabled'}) && $self->{'autoconfiguration_enabled'} == 1) {
my $agent_data = PandoraFMS::DB::get_db_single_row($self->{'dbh'}, 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id);
# Update agent configuration once, after create agent.
enterprise_hook('autoconfigure_agent', [$self->{'pa_config'}, $host_name, $agent_id, $agent_data, $self->{'dbh'}, 1]);
}
if (defined($self->{'main_event_id'})) {
my $addresses_str = join(',', safe_output($self->get_addresses($device)));
pandora_extended_event(
$self->{'pa_config'}, $self->{'dbh'}, $self->{'main_event_id'},
"[Discovery] New " . safe_output($self->get_device_type($device)) . " found " . $host_name . " (" . $addresses_str . ") Agent $agent_id."
);
}
$agent_learning = 1;
# Create network profile modules for the agent
$self->create_network_profile_modules($agent_id, $device);
}
else {
$agent_id = $agent->{'id_agente'};
$agent_learning = $agent->{'modo'};
}
# Do not create any modules if the agent is not in learning mode.
return unless ($agent_learning == 1);
# Add found IP addresses to the agent.
foreach my $ip_addr ($self->get_addresses($device)) {
my $addr_id = get_addr_id($self->{'dbh'}, $ip_addr);
$addr_id = add_address($self->{'dbh'}, $ip_addr) unless ($addr_id > 0);
next unless ($addr_id > 0);
# Assign the new address to the agent
my $agent_addr_id = get_agent_addr_id($self->{'dbh'}, $addr_id, $agent_id);
if ($agent_addr_id <= 0) {
db_do($self->{'dbh'}, 'INSERT INTO taddress_agent (`id_a`, `id_agent`)
VALUES (?, ?)', $addr_id, $agent_id);
}
}
# Create a ping module.
my $module_id = get_agent_module_id($self->{'dbh'}, "ping", $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 6,
'id_modulo' => 2,
'nombre' => "ping",
'descripcion' => '',
'id_agente' => $agent_id,
'ip_target' => $device);
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
}
# Add interfaces to the agent if it responds to SNMP.
return $agent_id unless ($self->is_snmp_discovered($device));
my $community = $self->get_community($device);
my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX);
foreach my $if_index (@output) {
next unless ($if_index =~ /^[0-9]+$/);
# Check the status of the interface.
if (!is_enabled($self->{'all_ifaces'})) {
my $if_status = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index");
next unless $if_status == 1;
}
# Fill the module description with the IP and MAC addresses.
my $mac = $self->get_if_mac($device, $if_index);
my $ip = $self->get_if_ip($device, $if_index);
my $if_desc = ($mac ne '' ? "MAC $mac " : '') . ($ip ne '' ? "IP $ip" : '');
# Get the name of the network interface.
my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index");
$if_name = "if$if_index" unless defined ($if_name);
$if_name =~ s/"//g;
$if_name = clean_blank($if_name);
# Check whether the module already exists.
my $module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id);
next if ($module_id > 0 && !$agent_learning);
# Encode problematic characters.
$if_desc = safe_input($if_desc);
# Interface status module.
$module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifOperStatus', $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 18,
'id_modulo' => 2,
'nombre' => safe_input($if_name)."_ifOperStatus",
'descripcion' => $if_desc,
'id_agente' => $agent_id,
'ip_target' => $device,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'snmp_community' => $community,
'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index"
);
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
} else {
my %module = (
'descripcion' => $if_desc,
'ip_target' => $device,
'snmp_community' => $community,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'tcp_send' => $self->{'snmp_version'},
);
pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
}
# Incoming traffic module.
my $if_hc_in_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
if (defined($if_hc_in_octets)) {
$module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCInOctets', $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 16,
'id_modulo' => 2,
'nombre' => safe_input($if_name)."_ifHCInOctets",
'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.',
'id_agente' => $agent_id,
'ip_target' => $device,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'snmp_community' => $community,
'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index");
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
} else {
my %module = (
'ip_target' => $device,
'snmp_community' => $community,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
);
pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
}
}
# ifInOctets
elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index"))) {
$module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifInOctets', $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 16,
'id_modulo' => 2,
'nombre' => safe_input($if_name)."_ifInOctets",
'descripcion' => 'The total number of octets received on the interface, including framing characters.',
'id_agente' => $agent_id,
'ip_target' => $device,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'snmp_community' => $community,
'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index");
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
} else {
my %module = (
'ip_target' => $device,
'snmp_community' => $community,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
);
pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
}
}
# Outgoing traffic module.
my $if_hc_out_octets = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
if (defined($if_hc_out_octets)) {
$module_id = get_agent_module_id($self->{'dbh'}, $if_name.'_ifHCOutOctets', $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 16,
'id_modulo' => 2,
'nombre' => safe_input($if_name)."_ifHCOutOctets",
'descripcion' => 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.',
'id_agente' => $agent_id,
'ip_target' => $device,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'snmp_community' => $community,
'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index");
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
} else {
my %module = (
'ip_target' => $device,
'snmp_community' => $community,
'tcp_send' => $self->{'snmp_version'},
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
);
pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
}
}
# ifOutOctets
elsif (defined($self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index"))) {
$module_id = get_agent_module_id($self->{'dbh'}, "${if_name}_ifOutOctets", $agent_id);
if ($module_id <= 0) {
my %module = ('id_tipo_modulo' => 16,
'id_modulo' => 2,
'nombre' => safe_input($if_name)."_ifOutOctets",
'descripcion' => 'The total number of octets received on the interface, including framing characters.',
'id_agente' => $agent_id,
'ip_target' => $device,
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
'snmp_community' => $community,
'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index");
pandora_create_module_from_hash ($self->{'pa_config'}, \%module, $self->{'dbh'});
} else {
my %module = (
'ip_target' => $device,
'snmp_community' => $community,
'tcp_send' => $self->{'snmp_version'},
'tcp_send' => $self->{'snmp_version'},
'custom_string_1' => $self->{'snmp_privacy_method'},
'custom_string_2' => $self->{'snmp_privacy_pass'},
'custom_string_3' => $self->{'snmp_security_level'},
'plugin_parameter' => $self->{'snmp_auth_method'},
'plugin_user' => $self->{'snmp_auth_user'},
'plugin_pass' => $self->{'snmp_auth_pass'},
);
pandora_update_module_from_hash ($self->{'pa_config'}, \%module, 'id_agente_modulo', $module_id, $self->{'dbh'});
}
}
}
return $agent_id;
}
################################################################################
# Delete already existing connections.
################################################################################

View File

@ -42,6 +42,10 @@ use constant {
DISCOVERY_REVIEW => 0,
DISCOVERY_STANDARD => 1,
DISCOVERY_RESULTS => 2,
WMI_UNREACHABLE => 1,
WMI_BAD_PASSWORD => 2,
WMI_GENERIC_ERROR => 3,
WMI_OK => 0,
};
# $DEVNULL
@ -398,13 +402,17 @@ sub are_connected($$$$$) {
}
################################################################################
# Initialize tmp pool for device.
# Already discovered by scan_subnet.
# Initialize tmp pool for addr.
# Already discovered by scan_subnet. Registration only.
################################################################################
sub icmp_discovery($$) {
my ($self, $addr) = @_;
$self->prepare_agent($addr);
# Create an agent for the device and add it to the list of known hosts.
push(@{$self->{'hosts'}}, $addr);
# Create an agent for the device and add it to the list of known hosts.
$self->add_agent($addr);
$self->add_module($addr,
{
@ -459,13 +467,6 @@ sub snmp_discovery($$) {
$self->snmp_pen($device);
}
}
# Create an agent for the device and add it to the list of known hosts.
push(@{$self->{'hosts'}}, $device);
# Create an agent for the device and add it to the list of known hosts.
$self->add_agent($device);
}
################################################################################
@ -1379,7 +1380,7 @@ sub test_capabilities($$) {
# WMI discovery.
if (is_enabled($self->{'wmi_enabled'})) {
# Add wmi scan if enabled.
$self->wmi_scan($addr);
$self->wmi_discovery($addr);
}
}
@ -2129,20 +2130,58 @@ sub traceroute_connectivity($$) {
# Returns the credentials with which the host responds to WMI queries or
# undef if it does not respond to WMI.
################################################################################
sub responds_to_wmi {
sub wmi_credentials {
my ($self, $target) = @_;
return $self->{'wmi_auth'}{$target};
}
################################################################################
# Calculate WMI credentials for target, 1 if calculated, undef if cannot
# connect to target. Credentials could be empty (-N)
################################################################################
sub wmi_credentials_calculation {
my ($self, $target) = @_;
foreach my $auth (@{$self->{'auth_strings_array'}}) {
my @output;
if ($auth ne '') {
@output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -U $auth //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`;
} else {
@output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -N //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`;
# Test empty credentials.
my @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -N //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`;
my $rs = $self->wmi_output_check($?, @output);
if ($rs == WMI_OK) {
$self->{'wmi_auth'}{$target} = '';
return 1;
}
if ($rs == WMI_UNREACHABLE) {
# Target does not respond.
$self->{'wmi'}{$target} = 0;
return undef;
}
# 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';
my $auth = $cred->{'username'}.'%'.$cred->{'password'};
next if $auth eq '%';
@output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -U $auth //$target "SELECT * FROM Win32_ComputerSystem" 2>&1`;
my $rs = $self->wmi_output_check($?, @output);
if ($rs == WMI_OK) {
$self->{'wmi_auth'}{$target} = $auth;
$self->{'wmi'}{$target} = 1;
$self->{'summary'}->{'WMI'} += 1;
$self->call('message', "[".$target."] WMI available.", 10);
return 1;
}
foreach my $line (@output) {
chomp($line);
return $auth if ($line =~ m/^CLASS: Win32_ComputerSystem$/);
if ($rs == WMI_UNREACHABLE) {
# Target does not respond.
$self->call('message', "[".$target."] WMI unreachable.", 10);
$self->{'wmi'}{$target} = 0;
return undef;
}
}
@ -2150,74 +2189,16 @@ sub responds_to_wmi {
}
################################################################################
# Add wmi modules to the given host.
# Tests wmi capability for addr.
################################################################################
sub wmi_scan {
my ($self, $target) = @_;
sub wmi_discovery {
my ($self, $addr) = @_;
$self->call('message', "[".$target."] Checking WMI.", 5);
# Initialization.
$self->{'wmi'} = {} unless ref($self->{'wmi'}) eq 'HASH';
my $auth = $self->responds_to_wmi($target);
return unless defined($auth);
$self->{'summary'}->{'WMI'} += 1;
$self->call('message', "[".$target."] WMI available.", 10);
# Register agent.
$self->add_agent($target);
# Add modules.
# CPU.
my @cpus = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceId FROM Win32_Processor', 0);
foreach my $cpu (@cpus) {
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'",
'auth' => $auth,
'column' => 1,
'name' => "CPU Load $cpu",
'description' => "Load for $cpu (%)",
'type' => 'generic_data',
'unit' => '%',
}
);
}
# Memory.
my $mem = $self->wmi_get_value($target, $auth, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0);
if (defined($mem)) {
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem",
'auth' => $auth,
'column' => 0,
'name' => 'FreeMemory',
'description' => 'Free memory',
'type' => 'generic_data',
'unit' => 'KB',
}
);
}
# Disk.
my @units = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceID FROM Win32_LogicalDisk', 0);
foreach my $unit (@units) {
$self->add_module($target,
{
'target' => $target,
'query' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'",
'auth' => $auth,
'column' => 1,
'name' => "FreeDisk $unit",
'description' => 'Available disk space in kilobytes',
'type' => 'generic_data',
'unit' => 'KB',
}
);
}
# Calculate credentials.
$self->wmi_credentials_calculation($addr);
}
@ -2225,10 +2206,52 @@ sub wmi_scan {
# Extra: WMI imported methods. DO NOT EXPORT TO AVOID DOUBLE DEF.
################################################################################
################################################################################
# Validate wmi output. (err code and messages).
################################################################################
sub wmi_output_check {
my ($self, $rc, @output) = @_;
if ($? != 0) {
# Something went wrong.
if (defined($output[-1]) && $output[-1] =~ /NTSTATUS: (.*)/) {
my $err = $1;
$self->{'last_wmi_error'} = $err;
if ($err =~ /NT_STATUS_IO_TIMEOUT/
|| $err =~ /NT_STATUS_CONNECTION_REFUSED/
) {
# Fail.
return WMI_UNREACHABLE;
}
if ($err =~ /NT_STATUS_ACCESS_DENIED/) {
return WMI_BAD_PASSWORD;
}
}
# Fail.
return WMI_GENERIC_ERROR;
}
# Ok.
return WMI_OK;
}
################################################################################
# Performs a wmi get requests and returns the response as an array.
################################################################################
sub wmi_get {
my ($self, $target, $query) = @_;
return () unless $self->wmi_responds($target);
return $self->wmi_get_command($target, $self->{'wmi_auth'}{$target}, $query);
}
################################################################################
# Performs a wmi get requests and returns the response as an array.
################################################################################
sub wmi_get_command {
my ($self, $target, $auth, $query) = @_;
my @output;
@ -2238,10 +2261,28 @@ sub wmi_get {
@output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -N //$target "$query" 2>&1`;
}
# Something went wrong.
return () if ($? != 0);
my $rs = $self->wmi_output_check($?, @output);
return @output;
if ($rs == WMI_OK) {
return @output;
}
$self->call(
'message',
"[".$target."] WMI error: ".$self->{'last_wmi_error'},
10
);
return ();
}
################################################################################
# Checks if target is reachable using wmi.
################################################################################
sub wmi_responds {
my ($self, $target) = @_;
return 1 if is_enabled($self->{'wmi'}{$target});
return 0;
}
################################################################################
@ -2249,10 +2290,10 @@ sub wmi_get {
# Returns undef on error.
################################################################################
sub wmi_get_value {
my ($self, $target, $auth, $query, $column) = @_;
my ($self, $target, $query, $column) = @_;
my @result;
my @output = $self->wmi_get($target, $auth, $query);
my @output = $self->wmi_get($target, $query);
return undef unless defined($output[2]);
my $line = $output[2];
@ -2268,10 +2309,10 @@ sub wmi_get_value {
# in an array.
################################################################################
sub wmi_get_value_array {
my ($self, $target, $auth, $query, $column) = @_;
my ($self, $target, $query, $column) = @_;
my @result;
my @output = $self->wmi_get($target, $auth, $query);
my @output = $self->wmi_get($target, $query);
foreach (my $i = 2; defined($output[$i]); $i++) {
my $line = $output[$i];
chomp($line);