diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index cbe5c93ed8..b6c3a073a9 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.744-200414 +Version: 7.0NG.744-200421 Architecture: all Priority: optional Section: admin diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index 68b1e4e171..e7fac4e3c3 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.744-200414" +pandora_version="7.0NG.744-200421" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/Linux/pandora_agent.conf b/pandora_agents/unix/Linux/pandora_agent.conf index 34f9d8e02b..52ca10f17b 100644 --- a/pandora_agents/unix/Linux/pandora_agent.conf +++ b/pandora_agents/unix/Linux/pandora_agent.conf @@ -254,6 +254,9 @@ module_plugin pandora_mem_used module_plugin pandora_netusage +# Service autodiscovery plugin +module_plugin autodiscover --default + # Plugin for inventory on the agent (Only Enterprise) #module_plugin inventory 1 cpu ram video nic hd cdrom software init_services filesystem users route diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 0280895693..30f059fa14 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -55,7 +55,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.744'; -use constant AGENT_BUILD => '200414'; +use constant AGENT_BUILD => '200421'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 6c7af89df6..270b3d9905 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.744 -%define release 200414 +%define release 200421 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index b96019b8e0..e0da66bfce 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -3,7 +3,7 @@ # %define name pandorafms_agent_unix %define version 7.0NG.744 -%define release 200414 +%define release 200421 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 4e5072610c..1b7bf5a232 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.744" -PI_BUILD="200414" +PI_BUILD="200421" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/bin/pandora_agent.conf b/pandora_agents/win32/bin/pandora_agent.conf index ba1e0b6444..774797aa4b 100644 --- a/pandora_agents/win32/bin/pandora_agent.conf +++ b/pandora_agents/win32/bin/pandora_agent.conf @@ -245,6 +245,10 @@ module_plugin cscript.exe //B "%ProgramFiles%\Pandora_Agent\util\network.vbs" #module_crontab * 12-15 * * 1 #module_end +# Service autodiscovery plugin +module_plugin "%PROGRAMFILES%\Pandora_Agent\util\autodiscover.exe" --default + + ######################################### # EXAMPLES # ######################################### diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index d823426c8f..97ca31d624 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{200414} +{200421} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 1e3c7a48a1..72a94ec828 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.744(Build 200414)") +#define PANDORA_VERSION ("7.0NG.744(Build 200421)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index ffb90a0619..8b8479ff25 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -11,7 +11,7 @@ BEGIN VALUE "LegalCopyright", "Artica ST" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.744(Build 200414))" + VALUE "ProductVersion", "(7.0NG.744(Build 200421))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 68255e4e05..6418ac56f0 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.744-200414 +Version: 7.0NG.744-200421 Architecture: all Priority: optional Section: admin diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index 84a4c8d67b..ebc8dcccad 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.744-200414" +pandora_version="7.0NG.744-200421" package_pear=0 package_pandora=1 diff --git a/pandora_console/include/ajax/events.php b/pandora_console/include/ajax/events.php index b926c5a13a..60c74e9731 100644 --- a/pandora_console/include/ajax/events.php +++ b/pandora_console/include/ajax/events.php @@ -917,9 +917,11 @@ if ($get_response) { if ($perform_event_response) { global $config; - $command = get_parameter('target', ''); - $response_id = get_parameter('response_id'); + $event_id = (int) get_parameter('event_id'); + $server_id = (int) get_parameter('server_id', 0); + + $command = events_get_response_target($event_id, $response_id, $server_id); $event_response = db_get_row('tevent_response', 'id', $response_id); @@ -1017,6 +1019,7 @@ if ($dialogue_event_response) { $show_execute_again_btn = get_parameter('show_execute_again_btn'); $out_iterator = get_parameter('out_iterator'); $event_response = db_get_row('tevent_response', 'id', $response_id); + $server_id = get_parameter('server_id'); $event = db_get_row('tevento', 'id_evento', $event_id); @@ -1067,7 +1070,8 @@ if ($dialogue_event_response) { echo "
"; echo "
'; } break; diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index e991767594..f8263b144d 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC200414'; +$build_version = 'PC200421'; $pandora_version = 'v7.0NG.744'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/include/javascript/pandora_events.js b/pandora_console/include/javascript/pandora_events.js index 8a2546ad09..e176b863ad 100644 --- a/pandora_console/include/javascript/pandora_events.js +++ b/pandora_console/include/javascript/pandora_events.js @@ -118,30 +118,26 @@ function execute_response(event_id, server_id) { } response["target"] = get_response_target(event_id, response_id, server_id); + response["event_id"] = event_id; + response["server_id"] = server_id; - switch (response["type"]) { - case "command": - show_response_dialog(event_id, response_id, response); - break; - case "url": - if (response["new_window"] == 1) { - window.open(response["target"], "_blank"); - } else { - show_response_dialog(event_id, response_id, response); - } - break; + if (response["type"] == "url" && response["new_window"] == 1) { + window.open(response["target"], "_blank"); + } else { + show_response_dialog(response_id, response); } } //Show the modal window of an event response -function show_response_dialog(event_id, response_id, response) { +function show_response_dialog(response_id, response) { var params = []; params.push("page=include/ajax/events"); params.push("dialogue_event_response=1"); params.push("massive=0"); - params.push("event_id=" + event_id); + params.push("event_id=" + response["event_id"]); params.push("target=" + response["target"]); params.push("response_id=" + response_id); + params.push("server_id=" + response["server_id"]); jQuery.ajax({ data: params.join("&"), @@ -159,7 +155,7 @@ function show_response_dialog(event_id, response_id, response) { draggable: true, modal: false, open: function() { - perform_response(response["target"], response_id); + perform_response(response, response_id); }, width: response["modal_width"], height: response["modal_height"] @@ -171,7 +167,6 @@ function show_response_dialog(event_id, response_id, response) { //Show the modal window of event responses when multiple events are selected function show_massive_response_dialog( - event_id, response_id, response, out_iterator, @@ -183,13 +178,14 @@ function show_massive_response_dialog( params.push("massive=1"); params.push("end=" + end); params.push("out_iterator=" + out_iterator); - params.push("event_id=" + event_id); + params.push("event_id=" + response["event_id"]); params.push("target=" + response["target"]); params.push("response_id=" + response_id); + params.push("server_id=" + response["server_id"]); jQuery.ajax({ data: params.join("&"), - response_tg: response["target"], + response_tg: response, response_id: response_id, out_iterator: out_iterator, type: "POST", @@ -384,7 +380,7 @@ function get_response_target( } // Perform a response and put the output into a div -function perform_response(target, response_id) { +function perform_response(response, response_id) { $("#re_exec_command").hide(); $("#response_loading_command").show(); $("#response_out").html(""); @@ -392,8 +388,10 @@ function perform_response(target, response_id) { var params = []; params.push("page=include/ajax/events"); params.push("perform_event_response=1"); - params.push("target=" + target); + params.push("target=" + response["target"]); params.push("response_id=" + response_id); + params.push("event_id=" + response["event_id"]); + params.push("server_id=" + response["server_id"]); jQuery.ajax({ data: params.join("&"), @@ -413,7 +411,7 @@ function perform_response(target, response_id) { } // Perform a response and put the output into a div -function perform_response_massive(target, response_id, out_iterator) { +function perform_response_massive(response, response_id, out_iterator) { $("#re_exec_command").hide(); $("#response_loading_command_" + out_iterator).show(); $("#response_out_" + out_iterator).html(""); @@ -421,8 +419,10 @@ function perform_response_massive(target, response_id, out_iterator) { var params = []; params.push("page=include/ajax/events"); params.push("perform_event_response=1"); - params.push("target=" + target); + params.push("target=" + response["target"]); params.push("response_id=" + response_id); + params.push("event_id=" + response["event_id"]); + params.push("server_id=" + response["server_id"]); jQuery.ajax({ data: params.join("&"), @@ -916,17 +916,24 @@ function check_massive_response_event( $(".chk_val:checked").each(function() { var event_id = $(this).val(); - var server_id = $("#hidden-server_id_" + event_id).val(); + var meta = $("#hidden-meta").val(); + var server_id = 0; + if (meta) { + server_id = $("#hidden-server_id_" + event_id).val(); + } + response["target"] = get_response_target( event_id, response_id, server_id, response_command ); + response["server_id"] = server_id; + response["event_id"] = event_id; if (total_checked - 1 === counter) end = 1; - show_massive_response_dialog(event_id, response_id, response, counter, end); + show_massive_response_dialog(response_id, response, counter, end); counter++; }); diff --git a/pandora_console/include/styles/task_list.css b/pandora_console/include/styles/task_list.css index 01f7a82549..c8a6f42aa8 100644 --- a/pandora_console/include/styles/task_list.css +++ b/pandora_console/include/styles/task_list.css @@ -110,3 +110,12 @@ span.link.review { padding-top: 2em; padding-left: 6.7em; } + +#review .sim-tree li.disabled > a .sim-tree-checkbox { + border-color: #eee; + background-color: #ddd; +} + +#task_review { + width: 100% !important; +} diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css index 3d66e165ff..69209ce17c 100644 --- a/pandora_console/include/styles/wizard.css +++ b/pandora_console/include/styles/wizard.css @@ -42,6 +42,10 @@ ul.wizard li > textarea { justify-content: space-between; } +.std_input.hidden { + display: none; +} + .wizard .std_input > .label_select { flex: 1 1 100%; } diff --git a/pandora_console/install.php b/pandora_console/install.php index 26de845c43..94ad69eeac 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -129,7 +129,7 @@
'; + if(item.meta === true) { + evn += ''; + } item.mini_severity = '
'; item.mini_severity += output; diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index c36a64c969..d16373cafc 100644 --- a/pandora_console/pandora_console.redhat.spec +++ b/pandora_console/pandora_console.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.744 -%define release 200414 +%define release 200421 # User and Group under which Apache is running %define httpd_name httpd diff --git a/pandora_console/pandora_console.rhel7.spec b/pandora_console/pandora_console.rhel7.spec index ea0486171b..bb3363e8a1 100644 --- a/pandora_console/pandora_console.rhel7.spec +++ b/pandora_console/pandora_console.rhel7.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.744 -%define release 200414 +%define release 200421 # User and Group under which Apache is running %define httpd_name httpd diff --git a/pandora_console/pandora_console.spec b/pandora_console/pandora_console.spec index 6843fd4f62..f08fb95c8f 100644 --- a/pandora_console/pandora_console.spec +++ b/pandora_console/pandora_console.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.744 -%define release 200414 +%define release 200421 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_plugins/Autodiscover services/autodiscover.py b/pandora_plugins/Autodiscover services/autodiscover.py new file mode 100644 index 0000000000..78a70cddba --- /dev/null +++ b/pandora_plugins/Autodiscover services/autodiscover.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python3 +################################################### +# +# Pandora FMS Autodiscovery plugin. +# Checks the status of the services in list and monitors CPU and Memory for each of them. +# +# (c) A. Kevin Rojas +# +# TO DO LIST: +# - Enable child services detection (Windows) +# - Make CPU/Memory usage available for child services (Windows) +# +################################################### + +from sys import argv, path, stderr, exit +import psutil +from subprocess import * + +global module_list +module_list = [] + + +######################################################################################### +# Powershell class +######################################################################################### +class PSCheck: + @staticmethod + def check_service(servicename, option=False, memcpu=False): + """Check services with powershell by parsing their DisplayName. Returns a dict\ + list with the name of the service and a boolean with its status.\n + Requires service name (case insensitive).""" + pscall = Popen(["powershell", "Get-Service", "-Name", "'*"+ str(servicename) + "*'", + "|", "Select-Object", "-ExpandProperty", "Name"], + stdout=PIPE, stdin=DEVNULL, stderr=DEVNULL, universal_newlines=True) + result = pscall.communicate() + result = str(result[0]).strip().split("\n") + procname = '' + if result != '': + output = [] + for element in result: + if element != '': + # Get process name + procname = PSCheck.get_serviceprocess(element) + # Get process status + parstatus = PSCheck.getstatus(element) + if memcpu == True and parstatus == 1: + usage = get_memcpu(str(procname), str(element)) + output += usage + # Generate module with name and status + parent = service_module(str(element), parstatus) + output += parent + if option == True: + children = PSCheck.getchildren(element, memcpu) + if type(children) == list and len(children) > 1: + for child in children: + output += child + else: + output += children + else: + next + + #if output != '': + if output and element and procname: + return ({"name" : element, "process" : procname, "modules": output}) + else: + return (None) + + @staticmethod + def getchildren(servicename, memcpu=False): + """Gets Dependent services of a given Windows service""" + pschild = Popen(["powershell", "Get-Service", "-Name '" + str(servicename) + + "' -DS", "|", "Select-Object", "-ExpandProperty", "Name"], + stdout=PIPE, stdin=DEVNULL, stderr=DEVNULL, universal_newlines=True) + children = pschild.communicate()[0].strip() + kids = [] + for child in (children.split("\n") if children != "" else []): + status = PSCheck.getstatus(child) + kids += service_module(str(child), status, "Service " + str(servicename) + " - Status") + if status: + if memcpu == True: + kidsusage = get_memcpu(str(child)) + for usage in kidsusage: + kids += usage + else: + next + return (kids) + + @staticmethod + def getstatus(servicename): + """Gets the status of a given Windows service""" + running = Popen(["powershell", "Get-Service", "-Name '" + str(servicename) + + "' |", "Select-Object", "-ExpandProperty", "Status"], + stdout=PIPE, stdin=DEVNULL, stderr=DEVNULL, universal_newlines=True) + status = running.communicate()[0].strip() + return (int(status == "Running")) + + @staticmethod + def get_serviceprocess(servicename): + """Gets name of the process of the service""" + service = psutil.win_service_get(servicename) + srv_pid = service.pid() + process = psutil.Process(srv_pid) + proc_name = process.name() + return (proc_name) + + +######################################################################################### +# Services creation +######################################################################################### + +def service_module(name, value, parent=None): + #print ("service_module BEGIN "+str(now(0,1))) + module = [{ + "name" : "Service "+ name + " - Status", + "type" : "generic_proc", + "value" : value, + "module_parent" : parent, + }] + #print ("service_module END "+str(now(0,1))) + return (module) + +def get_memcpu (process, servicename): + """Creates a module for Memory and CPU for a given process. Returns a list of dictionaries.""" + modules = [] + if process: + if servicename != None: + parentname = servicename + else: + parentname = process + modules += [{ + "name" : "Service "+ process + " - Memory usage", + "type" : "generic_data", + "value" : proc_percentbyname(process)[0], + "unit" : "%", + "module_parent" : "Service "+ parentname + " - Status", + }, + {"name" : "Service "+ process + " - CPU usage", + "type" : "generic_data", + "value" : proc_percentbyname(process)[1], + "unit" : "%", + "module_parent" : "Service "+ parentname + " - Status", + }] + return (modules) + +def proc_percentbyname(procname): ############# 03/03/2020 + """Gets Memory and CPU usage for a given process. Returns a list.""" + #print ("proc_percentbyname BEGIN "+str(now(0,1))) + procs = [p for p in psutil.process_iter() if procname in p.name().lower()] + memory = [] + cpu = [] + try: + for proc in procs: + if proc.name() == procname: + cpu.append(proc.cpu_percent(interval=0.5)) + memory.append(proc.memory_percent()) + else: + next + except psutil.NoSuchProcess: + next + #print ("proc_percentbyname END "+str(now(0,1))) + return ([sum(memory),sum(cpu)]) + +def win_service(servicelist, option=False, memcpu=False): + """Creates modules for Windows servers.""" + modules = [] + for srvc in servicelist: + if srvc and len(srvc) > 2: + output = PSCheck.check_service(srvc, option, memcpu) + if output != None and output["modules"]: + modules += PSCheck.check_service(srvc.strip(), option, memcpu)["modules"] + module_list.append(srvc) + winprocess = output["name"] + #if memcpu == True: + # modules += get_memcpu(winprocess) ## Only available for parent service ATM. + else: + next + else: + next + for module in modules: + print_module(module, 1) + + +def lnx_service(services_list, memcpu=False): + """Creates modules for Linux servers""" + modules = [] + sysctl = getstatusoutput("command -v systemctl")[0] + servic = getstatusoutput("command -v service")[0] + for srvc in services_list: + status = None + if sysctl == 0: + ### Systemd available + syscall = Popen(["systemctl", "is-active", srvc], stdout=PIPE, + stdin=DEVNULL, universal_newlines=True) + result = syscall.communicate() + result = result[0].strip().lower() + if result == "active": + modules += service_module(srvc, 1) + status = 1 + elif result == "inactive": + modules += service_module(srvc, 0) + status = 0 + elif result == "unknown": + next + elif sysctl != 0 and servic == 0: + ### Systemd not available, switch to service command + syscall = Popen(["service", srvc, "status"], stdout=PIPE, + stdin=DEVNULL, stderr=DEVNULL, universal_newlines=True) + result = syscall.communicate()[0].lower() + if "is running" in result: + modules += service_module(srvc, 1) + status = 1 + elif "is stopped" in result: + modules += service_module(srvc, 0) + status = 0 + else: + next + else: + print ("No systemd or service commands available. Exiting...", file=stderr) + exit() + if status: + module_list.append(srvc) + if memcpu == True: + modules += get_memcpu(srvc, None) + + for m in modules: + print_module (m, 1) + + +######################################################################################### +# print_module function +######################################################################################### +def print_module(module, str_flag=False): + """Returns module in XML format. Accepts only {dict}.\n + + Only works with one module at a time: otherwise iteration is needed. + + Module "value" field accepts str type or [list] for datalists. + + Use not_print_flag to avoid printing the XML (only populates variables). + """ + data = dict(module) + module_xml = ("\n" + "\t\n" + "\t" + str(data["type"]) + "\n" + ) + #### Strip spaces if module not generic_data_string + if type(data["type"]) is not str and "string" not in data["type"]: + data["value"] = data["value"].strip() + if isinstance(data["value"], list): # Checks if value is a list + module_xml += "\t\n" + for value in data["value"]: + if type(value) is dict and "value" in value: + module_xml += "\t\n" + module_xml += "\t\t\n" + if "timestamp" in value: + module_xml += "\t\t\n" + module_xml += "\t\n" + else: + module_xml += "\t\n" + if "desc" in data: + module_xml += "\t\n" + if "unit" in data: + module_xml += "\t\n" + if "interval" in data: + module_xml += "\t\n" + if "tags" in data: + module_xml += "\t" + str(data["tags"]) + "\n" + if "module_group" in data: + module_xml += "\t" + str(data["module_group"]) + "\n" + if "module_parent" in data and data["module_parent"] != None: + module_xml += "\t" + str(data["module_parent"]) + "\n" + if "min_warning" in data: + module_xml += "\t\n" + if "max_warning" in data: + module_xml += "\t\n" + if "min_critical" in data: + module_xml += "\t\n" + if "max_critical" in data: + module_xml += "\t\n" + if "str_warning" in data: + module_xml += "\t\n" + if "str_critical" in data: + module_xml += "\t\n" + if "critical_inverse" in data: + module_xml += "\t\n" + if "warning_inverse" in data: + module_xml += "\t\n" + if "max" in data: + module_xml += "\t\n" + if "min" in data: + module_xml += "\t\n" + if "post_process" in data: + module_xml += "\t\n" + if "disabled" in data: + module_xml += "\t\n" + if "min_ff_event" in data: + module_xml += "\t\n" + if "status" in data: + module_xml += "\t\n" + if "timestamp" in data: + module_xml += "\t\n" + if "custom_id" in data: + module_xml += "\t\n" + if "critical_instructions" in data: + module_xml += "\t\n" + if "warning_instructions" in data: + module_xml += "\t\n" + if "unknown_instructions" in data: + module_xml += "\t\n" + if "quiet" in data: + module_xml += "\t\n" + if "module_ff_interval" in data: + module_xml += "\t\n" + if "crontab" in data: + module_xml += "\t\n" + if "min_ff_event_normal" in data: + module_xml += "\t\n" + if "min_ff_event_warning" in data: + module_xml += "\t\n" + if "min_ff_event_critical" in data: + module_xml += "\t\n" + if "ff_type" in data: + module_xml += "\t\n" + if "ff_timeout" in data: + module_xml += "\t\n" + if "each_ff" in data: + module_xml += "\t\n" + if "module_parent_unlink" in data: + module_xml += "\t\n" + if "global_alerts" in data: + for alert in data["alert"]: + module_xml += "\t\n" + module_xml += "\n" + + #### Print flag + if str_flag is not False: + print (module_xml) + + return (module_xml) + + +######################################################################################### +# MAIN +######################################################################################### + +def main(): + """Checks OS and calls the discover function.""" + if psutil.WINDOWS: + OS = "Windows" + service_list = ["MySQL", "postgresql", "pgsql", "oracle", "MSSQL", "IISADMIN", + "apache", "nginx", "W3svc", "NTDS", "Netlogon", "DNS", "MSExchangeADTopology", + "MSExchangeServiceHost", "MSExchangeSA", "MSExchangeTransport"] + discover(OS, service_list) + elif psutil.LINUX: + OS = "Linux" + service_list = ["httpd", "apache2", "nginx", "ldap", "docker", + "postfix", "mysqld", "postgres", "oracle", "mongod"] + discover(OS, service_list) + else: + print ("OS not recognized. Exiting...", file=stderr) + exit() + +def discover(osyst, servicelist): + """Shows help and triggers the creation of service modules""" + if "--usage" in argv: + memcpu = True + else: + memcpu = False + if len(argv) > 2 and argv[1] == "--list": + servicelist = argv[2].split(",") + if osyst == "Windows": + win_service(servicelist, False, memcpu) ## False won't get children + elif osyst == "Linux": + lnx_service(servicelist, memcpu) + elif len(argv) > 1 and argv[1] == "--default": + if osyst == "Windows": + win_service(servicelist, False, memcpu) ## False won't get children + elif osyst == "Linux": + lnx_service(servicelist, memcpu) + else: + print ("\nPandora FMS Autodiscovery plugin.") + print ("Checks the status of the services in list and monitors CPU and Memory for each of them.\n") + print ("Usage:") + print ("{} [options] [--usage]".format(argv[0])) + print ("--help") + print ("\tPrints this help screen") + print ("--default") + print ("\tRuns this tool with default monitoring.".format(argv[0])) + print ("\tServices monitored by default for {}:".format(osyst)) + print ("\t",", ".join(servicelist)) + print ("--list \"\"") + print ("\tReplaces default services for a given list (comma-separated)") + if osyst == "Windows": + print ("\tEach element of the list will be treated as a regexp, but they must be over 2 characters.") + print ("\tElements under 2 characters will be discarded.") + print ("--usage") + print ("\tAdds modules for CPU and Memory usage per service/process (optional, can take some time).\n") + + +##### RUN #### +main() \ No newline at end of file diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 3f9a16fafa..ed3ff03cf7 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.744-200414 +Version: 7.0NG.744-200421 Architecture: all Priority: optional Section: admin diff --git a/pandora_server/DEBIAN/make_deb_package.sh b/pandora_server/DEBIAN/make_deb_package.sh index cc120882c3..7de21123f4 100644 --- a/pandora_server/DEBIAN/make_deb_package.sh +++ b/pandora_server/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.744-200414" +pandora_version="7.0NG.744-200421" package_cpan=0 package_pandora=1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index 78d7a80081..897ec8bfcb 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -45,7 +45,7 @@ our @EXPORT = qw( # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.744"; -my $pandora_build = "200414"; +my $pandora_build = "200421"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm index b395ec9574..7319e4f161 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -931,10 +931,12 @@ sub pandora_execute_alert ($$$$$$$$$;$$) { $pa_config, "$text (" . safe_output($alert->{'name'}) . ") " . (defined ($module) ? 'assigned to ('. safe_output($module->{'nombre'}) . ")" : ""), (defined ($agent) ? $agent->{'id_grupo'} : 0), - (defined ($agent) ? $agent->{'id_agente'} : 0), + # id agent. + 0, $severity, (defined ($alert->{'id_template_module'}) ? $alert->{'id_template_module'} : 0), - (defined ($alert->{'id_agent_module'}) ? $alert->{'id_agent_module'} : 0), + # id agent module. + 0, $event, 0, $dbh, @@ -4206,7 +4208,9 @@ sub on_demand_macro($$$$$$;$) { my $unit_mod = get_db_value ($dbh, 'SELECT unit FROM tagente_modulo WHERE id_agente_modulo = ?', $id_mod); my $field_value = ""; - if ($type_mod eq 3 || $type_mod eq 23|| $type_mod eq 17 || $type_mod eq 10 || $type_mod eq 33 ){ + if (defined($type_mod) + && ($type_mod eq 3 || $type_mod eq 23|| $type_mod eq 17 || $type_mod eq 10 || $type_mod eq 33 ) + ) { $field_value = get_db_value($dbh, 'SELECT datos FROM tagente_datos_string where id_agente_modulo = ? order by utimestamp desc limit 1', $id_mod); } else{ diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm index 903a9014c3..8cee68d538 100644 --- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm +++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm @@ -1019,35 +1019,63 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { # Agent creation. my $agent_id = $data->{'agent'}{'agent_id'}; my $agent_learning; + my $agent_data; if (defined($agent_id) && $agent_id > 0) { - $agent_learning = get_db_value( + $agent_data = get_db_single_row( $self->{'dbh'}, - 'SELECT modo FROM tagente WHERE id_agente = ?', + 'SELECT * FROM tagente WHERE id_agente = ?', $agent_id ); + $agent_learning = $agent_data->{'modo'} if ref($agent_data) eq 'HASH'; } if (!defined($agent_learning)) { # Agent id does not exists or is invalid. - # Check if has been created by another process. - $agent_id = get_db_value( - $self->{'dbh'}, - 'SELECT id_agente FROM tagente WHERE nombre = ?', - safe_input($data->{'agent'}{'nombre'}) - ); + # Check if has been created by another process, if not found. + $agent_data = PandoraFMS::Core::locate_agent( + $self->{'pa_config'}, $self->{'dbh'}, $data->{'agent'}{'direccion'} + ) if ref($agent_data) ne 'HASH'; - if (!defined($agent_id) || $agent_id <= 0) { + $agent_id = $agent_data->{'id_agente'} if ref($agent_data) eq 'HASH'; + if (ref($agent_data) eq 'HASH' && $agent_data->{'modo'} != 1) { + # Agent previously exists, but is not in learning mode, so skip + # modules scan and jump directly to parent analysis. + $data->{'agent'}{'agent_id'} = $agent_id; + push @agents, $data->{'agent'}; + next; + } + + if (!defined($agent_id) || $agent_id <= 0 || !defined($agent_data)) { # Agent creation. $agent_id = pandora_create_agent( $self->{'pa_config'}, $self->{'servername'}, $data->{'agent'}{'nombre'}, $data->{'agent'}{'direccion'}, $self->{'task_data'}{'id_group'}, $parent_id, $os_id, $data->{'agent'}->{'description'}, $data->{'agent'}{'interval'}, $self->{'dbh'}, - $data->{'agent'}{'timezone_offset'} + $data->{'agent'}{'timezone_offset'}, undef, undef, undef, undef, + undef, undef, 1, $data->{'agent'}{'alias'} ); + # Add found IP addresses to the agent. + if (ref($data->{'other_ips'}) eq 'ARRAY') { + foreach my $ip_addr (@{$data->{'other_ips'}}) { + 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 + ); + } + } + } + # Agent autoconfiguration. if (is_enabled($self->{'autoconfiguration_enabled'})) { my $agent_data = PandoraFMS::DB::get_db_single_row( @@ -1093,6 +1121,25 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { 'SELECT modo FROM tagente WHERE id_agente = ?', $agent_id ); + + # Update new IPs. + # Add found IP addresses to the agent. + if (ref($data->{'other_ips'}) eq 'ARRAY') { + foreach my $ip_addr (@{$data->{'other_ips'}}) { + 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 + ); + } + } + } } $data->{'agent'}{'agent_id'} = $agent_id; @@ -1215,12 +1262,10 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { ); } - } # Update parent relationships. foreach my $agent (@agents) { - # Avoid processing if does not exist. next unless (defined($agent->{'agent_id'})); @@ -1228,10 +1273,10 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { next unless defined($agent->{'parent'}); # Get parent id. - my $parent = get_agent_from_addr($self->{'dbh'}, $agent->{'parent'}); - if (!defined($parent)) { - $parent = get_agent_from_name($self->{'dbh'}, $agent->{'parent'}); - } + my $parent = PandoraFMS::Core::locate_agent( + $self->{'pa_config'}, $self->{'dbh'}, $agent->{'parent'} + ); + next unless defined($parent); # Is the agent in learning mode? @@ -1286,7 +1331,12 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { my @hosts = keys %{$self->{'agents_found'}}; $self->{'step'} = STEP_PROCESSING; my ($progress, $step) = (90, 10.0 / scalar(@hosts)); # From 90% to 100%. - foreach my $label (keys %{$self->{'agents_found'}}) { + + foreach my $addr (keys %{$self->{'agents_found'}}) { + my $label = $self->{'agents_found'}->{$addr}{'agent'}{'nombre'}; + + next if is_empty($label); + $self->call('update_progress', $progress); $progress += $step; # Store temporally. Wait user approval. @@ -1294,7 +1344,7 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { eval { local $SIG{__DIE__}; $encoded = encode_base64( - encode_json($self->{'agents_found'}->{$label}) + encode_json($self->{'agents_found'}->{$addr}) ); }; @@ -1307,7 +1357,7 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { if (defined($id)) { # Already defined. - $self->{'agents_found'}{$label}{'id'} = $id; + $self->{'agents_found'}{$addr}{'id'} = $id; db_do( $self->{'dbh'}, @@ -1321,7 +1371,7 @@ sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { } # Insert. - $self->{'agents_found'}{$label}{'id'} = db_insert( + $self->{'agents_found'}{$addr}{'id'} = db_insert( $self->{'dbh'}, 'id', 'INSERT INTO tdiscovery_tmp_agents (`id_rt`,`label`,`data`,`created`) ' @@ -1615,6 +1665,16 @@ sub PandoraFMS::Recon::Base::set_parent($$$) { $self->{'agents_found'}{$host}{'agent'}{'parent'} = $parent; + # Add host alive module for parent. + $self->add_module($parent, + { + 'ip_target' => $parent, + 'name' => "Host Alive", + 'description' => '', + 'type' => 'remote_icmp_proc', + 'id_modulo' => 2, + } + ); } ################################################################################ diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index fb688f9c61..2d5ff32ed7 100644 --- a/pandora_server/lib/PandoraFMS/PluginTools.pm +++ b/pandora_server/lib/PandoraFMS/PluginTools.pm @@ -33,7 +33,7 @@ our @ISA = qw(Exporter); # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.744"; -my $pandora_build = "200414"; +my $pandora_build = "200421"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/lib/PandoraFMS/Recon/Base.pm b/pandora_server/lib/PandoraFMS/Recon/Base.pm index 01f8e824b8..4b3a920f9f 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -8,6 +8,7 @@ use warnings; # Default lib dir for RPM and DEB packages use NetAddr::IP; +use IO::Socket::INET; use POSIX qw/ceil/; use Socket qw/inet_aton/; @@ -171,6 +172,9 @@ sub new { # Visited devices (initially empty). visited_devices => {}, + # Inverse relationship for visited devices (initially empty). + addresses => {}, + # Per device VLAN cache. vlan_cache => {}, vlan_cache_enabled => 1, # User configuration. Globally disables the VLAN cache. @@ -308,6 +312,26 @@ sub add_addresses($$$) { my ($self, $device, $ip_address) = @_; $self->{'visited_devices'}->{$device}->{'addr'}->{$ip_address} = ''; + + # Inverse relationship. + $self->{'addresses'}{$ip_address} = $device; + + # Update IP references. + if (ref($self->{'agents_found'}{$device}) eq 'HASH') { + my @addresses = $self->get_addresses($device); + $self->{'agents_found'}{$device}{'other_ips'} = \@addresses; + $self->call('message', 'New IP detected for '.$device.': '.$ip_address, 5); + } + +} + +################################################################################ +# Get main address from given address (multi addressed devices). +################################################################################ +sub get_main_address($$) { + my ($self, $addr) = @_; + + return $self->{'addresses'}{$addr}; } ################################################################################ @@ -1320,17 +1344,30 @@ sub remote_arp($$) { ################################################################################ sub prepare_agent($$) { my ($self, $addr) = @_; + + # Avoid multi-ip agent. No reference, is first encounter. + my $main_address = $self->get_main_address($addr); + return unless is_empty($main_address); + + # Resolve hostnames. + my $host_name = (($self->{'resolve_names'} == 1) ? gethostbyaddr(inet_aton($addr), AF_INET) : $addr); + + # Fallback to device IP if host name could not be resolved. + $host_name = $addr if (!defined($host_name) || $host_name eq ''); + $self->{'agents_found'} = {} if ref($self->{'agents_found'}) ne 'HASH'; # Already initialized. - return if ref($self->{'agents_found'}->{$addr}) eq 'HASH'; + return if ref($self->{'agents_found'}->{$host_name}) eq 'HASH'; + my @addresses = $self->get_addresses($addr); $self->{'agents_found'}->{$addr} = { 'agent' => { - 'nombre' => $addr, + 'nombre' => $host_name, 'direccion' => $addr, - 'alias' => $addr, + 'alias' => $host_name, }, + 'other_ips' => \@addresses, 'pen' => $self->{'pen'}{$addr}, 'modules' => [], }; diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index 11ddf8372e..a495dc6096 100644 --- a/pandora_server/pandora_server.redhat.spec +++ b/pandora_server/pandora_server.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.744 -%define release 200414 +%define release 200421 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index cbffcc09bb..891fff1f09 100644 --- a/pandora_server/pandora_server.spec +++ b/pandora_server/pandora_server.spec @@ -3,7 +3,7 @@ # %define name pandorafms_server %define version 7.0NG.744 -%define release 200414 +%define release 200421 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index dd6b406114..1556356131 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.744" -PI_BUILD="200414" +PI_BUILD="200421" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index 0cbbf01fb7..b78f65bfc8 100644 --- a/pandora_server/util/pandora_db.pl +++ b/pandora_server/util/pandora_db.pl @@ -35,7 +35,7 @@ use PandoraFMS::Config; use PandoraFMS::DB; # version: define current version -my $version = "7.0NG.744 PS200414"; +my $version = "7.0NG.744 PS200421"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index ab784928d4..0522bd2810 100755 --- a/pandora_server/util/pandora_manage.pl +++ b/pandora_server/util/pandora_manage.pl @@ -36,7 +36,7 @@ use Encode::Locale; Encode::Locale::decode_argv; # version: define current version -my $version = "7.0NG.744 PS200414"; +my $version = "7.0NG.744 PS200421"; # save program name for logging my $progname = basename($0);