diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 620811d958..cbe5c93ed8 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-200413 +Version: 7.0NG.744-200414 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 b9b3c894fd..68b1e4e171 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-200413" +pandora_version="7.0NG.744-200414" 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 52ca10f17b..34f9d8e02b 100644 --- a/pandora_agents/unix/Linux/pandora_agent.conf +++ b/pandora_agents/unix/Linux/pandora_agent.conf @@ -254,9 +254,6 @@ 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 0929056b0e..0280895693 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 => '200413'; +use constant AGENT_BUILD => '200414'; # 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 f8dc6591df..6c7af89df6 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 200413 +%define release 200414 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 9b5f041e13..b96019b8e0 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 200413 +%define release 200414 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 43e57913e8..4e5072610c 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="200413" +PI_BUILD="200414" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/unix/plugins/autodiscover b/pandora_agents/unix/plugins/autodiscover deleted file mode 100644 index cbe4de677e..0000000000 Binary files a/pandora_agents/unix/plugins/autodiscover and /dev/null differ diff --git a/pandora_agents/win32/bin/pandora_agent.conf b/pandora_agents/win32/bin/pandora_agent.conf index 774797aa4b..ba1e0b6444 100644 --- a/pandora_agents/win32/bin/pandora_agent.conf +++ b/pandora_agents/win32/bin/pandora_agent.conf @@ -245,10 +245,6 @@ 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/bin/util/autodiscover.exe b/pandora_agents/win32/bin/util/autodiscover.exe deleted file mode 100644 index 41b7bf3629..0000000000 Binary files a/pandora_agents/win32/bin/util/autodiscover.exe and /dev/null differ diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 61074a602b..d823426c8f 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{200413} +{200414} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index c497ebd0b4..1e3c7a48a1 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 200413)") +#define PANDORA_VERSION ("7.0NG.744(Build 200414)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index c557f2030a..ffb90a0619 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 200413))" + VALUE "ProductVersion", "(7.0NG.744(Build 200414))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/.htaccess b/pandora_console/.htaccess index 593204bd27..a1e6f62d2d 100644 --- a/pandora_console/.htaccess +++ b/pandora_console/.htaccess @@ -1,2 +1,8 @@ # pandora disable listing -Options -Indexes \ No newline at end of file +Options -Indexes + + +Order Allow,Deny +Deny from All + + diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 18e85bb809..68255e4e05 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.744-200413 +Version: 7.0NG.744-200414 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 86a5a758d9..84a4c8d67b 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-200413" +pandora_version="7.0NG.744-200414" package_pear=0 package_pandora=1 diff --git a/pandora_console/extras/mr/37.sql b/pandora_console/extras/mr/37.sql index e3154fe0fb..60272f6a0c 100644 --- a/pandora_console/extras/mr/37.sql +++ b/pandora_console/extras/mr/37.sql @@ -2,6 +2,53 @@ START TRANSACTION; ALTER TABLE tagente_modulo MODIFY COLUMN `custom_string_1` MEDIUMTEXT; +ALTER TABLE `trecon_task` MODIFY COLUMN `id_network_profile` TEXT; +ALTER TABLE `trecon_task` CHANGE COLUMN `create_incident` `review_mode` TINYINT(1) UNSIGNED DEFAULT 0; +ALTER TABLE `trecon_task` ADD COLUMN `subnet_csv` TINYINT(1) UNSIGNED DEFAULT 1; + +UPDATE `trecon_task` SET `review_mode` = 1; +ALTER TABLE trecon_task add column `auto_monitor` TINYINT(1) UNSIGNED DEFAULT 1 AFTER `auth_strings`; +UPDATE `trecon_task` SET `auto_monitor` = 0; + +CREATE TABLE `tdiscovery_tmp_agents` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `label` varchar(600) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `data` MEDIUMTEXT, + `review_date` datetime DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `id_rt` (`id_rt`), + INDEX `label` (`label`), + CONSTRAINT `tdta_trt` FOREIGN KEY (`id_rt`) REFERENCES `trecon_task` (`id_rt`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `tdiscovery_tmp_connections` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `dev_1` text, + `dev_2` text, + `if_1` text, + `if_2` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `tpen` ( + `pen` int(10) unsigned NOT NULL, + `manufacturer` TEXT, + `description` TEXT, + PRIMARY KEY (`pen`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `tnetwork_profile_pen` ( + `pen` int(10) unsigned NOT NULL, + `id_np` int(10) unsigned NOT NULL, + CONSTRAINT `fk_network_profile_pen_pen` FOREIGN KEY (`pen`) + REFERENCES `tpen` (`pen`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `fk_network_profile_pen_id_np` FOREIGN KEY (`id_np`) + REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + ALTER TABLE `twidget_dashboard` ADD COLUMN `position` TEXT NOT NULL default ''; ALTER TABLE `tagente_estado` ADD COLUMN `last_status_change` bigint(20) NOT NULL default '0'; @@ -12,4 +59,111 @@ ALTER TABLE `talert_templates` ADD COLUMN `disable_event` tinyint(1) DEFAULT 0; ALTER TABLE `tevent_alert` ADD COLUMN `disable_event` tinyint(1) DEFAULT 0; ALTER TABLE `talert_snmp` ADD COLUMN `disable_event` tinyint(1) DEFAULT 0; +UPDATE twidget SET description='Show a visual console' WHERE class_name='MapsMadeByUser'; +UPDATE twidget SET description='Clock' WHERE class_name='ClockWidget'; +UPDATE twidget SET description='Group status' WHERE class_name='SystemGroupStatusWidget'; + +INSERT IGNORE INTO `tpen` VALUES (9,'cisco','Cisco System'),(11,'hp','Hewlett Packard'),(2021,'general_snmp','U.C. Davis, ECE Dept. Tom'),(2636,'juniper','Juniper Networks'),(3375,'f5','F5 Labs'),(8072,'general_snmp','Net SNMP'),(12356,'fortinet','Fortinet'); + +SET @template_name = 'Network Management'; +SET @template_description = 'Basic network monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Network Management')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Cisco MIBS'; +SET @template_description = 'Cisco devices monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Cisco MIBS' OR g.name = 'Catalyst 2900')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 9)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Linux System'; +SET @template_description = 'Linux system monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); + +SET @module_group = 'Linux'; + +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Linux' OR g.name = 'UCD Mibs (Linux, UCD-SNMP)')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 2021 OR p.pen = 2636)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Windows System'; +SET @template_description = 'Windows system monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Microsoft Windows' OR g.name = 'Windows System')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Hardware'; +SET @template_description = 'Windows hardware monitoring templae (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Hardware Layer')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Active Directory'; +SET @template_description = 'Active directory monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows AD' OR g.name = 'AD Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows IIS'; +SET @template_description = 'IIS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows IIS' OR g.name = 'IIS services')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Exchange'; +SET @template_description = 'Exchange monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Exchange' OR g.name = 'Exchange Services' OR g.name = 'Exchange TCP Ports')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows LDAP'; +SET @template_description = 'LDAP monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows LDAP')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MDSTC'; +SET @template_description = 'MDSTC monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows MSDTC')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Printers'; +SET @template_description = 'Windows printers monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Printers')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows DNS'; +SET @template_description = 'Windows DNS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows DNS' OR g.name = 'DNS Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MS SQL Server'; +SET @template_description = 'MS SQL Server monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MS SQL Server')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Oracle'; +SET @template_description = 'Oracle monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Oracle')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'MySQL'; +SET @template_description = 'MySQL monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MySQL')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Antivirus'; +SET @template_description = 'Windows antivirus monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Norton' OR g.name = 'Panda' OR g.name = 'McAfee' OR g.name = 'Bitdefender' OR g.name = 'BullGuard' OR g.name = 'AVG' OR g.name = 'Kaspersky')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + COMMIT; diff --git a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql index 2854b9e6c8..abfbdb4f96 100644 --- a/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql +++ b/pandora_console/extras/pandoradb_migrate_6.0_to_7.0.mysql.sql @@ -1477,6 +1477,28 @@ ALTER TABLE tnetwork_component ADD COLUMN `dynamic_two_tailed` tinyint(1) unsign ALTER TABLE `tnetwork_component` ADD COLUMN `ff_type` tinyint(1) unsigned default '0'; ALTER TABLE `tnetwork_component` MODIFY COLUMN `ff_type` tinyint(1) unsigned NULL DEFAULT '0'; +-- ---------------------------------------------------------------------- +-- Table `tpen` +-- ---------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tpen` ( + `pen` int(10) unsigned NOT NULL, + `manufacturer` TEXT, + `description` TEXT, + PRIMARY KEY (`pen`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnetwork_profile_pen` +-- ---------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tnetwork_profile_pen` ( + `pen` int(10) unsigned NOT NULL, + `id_np` int(10) unsigned NOT NULL, + CONSTRAINT `fk_network_profile_pen_pen` FOREIGN KEY (`pen`) + REFERENCES `tpen` (`pen`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `fk_network_profile_pen_id_np` FOREIGN KEY (`id_np`) + REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- --------------------------------------------------------------------- -- Table `tagente` -- --------------------------------------------------------------------- @@ -1662,7 +1684,39 @@ ALTER TABLE `trecon_task` ADD COLUMN `type` int(11) NOT NULL DEFAULT '0', MODIFY COLUMN `wmi_enabled` tinyint(1) unsigned NULL DEFAULT '0', MODIFY COLUMN `auth_strings` text NULL, MODIFY COLUMN `autoconfiguration_enabled` tinyint(1) unsigned NULL DEFAULT '0', - MODIFY COLUMN `summary` text NULL; + MODIFY COLUMN `summary` text NULL, + MODIFY COLUMN `id_network_profile` text, + CHANGE COLUMN `create_incident` `review_mode` TINYINT(1) UNSIGNED DEFAULT 1, + ADD COLUMN `subnet_csv` TINYINT(1) UNSIGNED DEFAULT 0; + +-- Old recon always report. +UPDATE `trecon_task` SET `review_mode` = 1; + +-- ---------------------------------------------------------------------- +-- Table `tdiscovery_tmp` +-- ---------------------------------------------------------------------- +CREATE TABLE `tdiscovery_tmp_agents` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `label` varchar(600) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `data` MEDIUMTEXT, + `review_date` datetime DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `id_rt` (`id_rt`), + INDEX `label` (`label`), + CONSTRAINT `tdta_trt` FOREIGN KEY (`id_rt`) REFERENCES `trecon_task` (`id_rt`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `tdiscovery_tmp_connections` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `dev_1` text, + `dev_2` text, + `if_1` text, + `if_2` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --------------------------------------------------------------------- -- Table `twidget` AND Table `twidget_dashboard` @@ -2129,6 +2183,8 @@ ALTER TABLE `trecon_task` ADD COLUMN `snmp_auth_method` varchar(25) NOT NULL def ALTER TABLE `trecon_task` ADD COLUMN `snmp_privacy_method` varchar(25) NOT NULL default ''; ALTER TABLE `trecon_task` ADD COLUMN `snmp_privacy_pass` varchar(255) NOT NULL default ''; ALTER TABLE `trecon_task` ADD COLUMN `snmp_security_level` varchar(25) NOT NULL default ''; +ALTER TABLE trecon_task add column `auto_monitor` TINYINT(1) UNSIGNED DEFAULT 1 AFTER `auth_strings`; +UPDATE `trecon_task` SET `auto_monitor` = 0; -- --------------------------------------------------------------------- -- Table `tagent_custom_fields_filter` @@ -2537,3 +2593,132 @@ INSERT INTO `tnetwork_component` (`name`, `description`, `id_group`, `type`, `ma INSERT INTO `tnetwork_component` (`name`, `description`, `id_group`, `type`, `max`, `min`, `module_interval`, `tcp_port`, `tcp_send`, `tcp_rcv`, `snmp_community`, `snmp_oid`, `id_module_group`, `id_modulo`, `id_plugin`, `plugin_user`, `plugin_pass`, `plugin_parameter`, `max_timeout`, `max_retries`, `history_data`, `min_warning`, `max_warning`, `max_critical`, `str_warning`, `min_ff_event`, `min_critical`, `custom_string_2`, `str_critical`, `custom_integer_1`, `custom_string_1`, `post_process`, `custom_string_3`, `wizard_level`, `custom_integer_2`, `critical_instructions`, `unit`, `unknown_instructions`, `macros`, `warning_inverse`, `warning_instructions`, `tags`, `critical_inverse`, `module_macros`, `id_category`, `min_ff_event_warning`, `disabled_types_event`, `ff_type`, `min_ff_event_normal`, `dynamic_interval`, `min_ff_event_critical`, `dynamic_min`, `each_ff`, `dynamic_two_tailed`, `dynamic_max`, `dynamic_next`) VALUES ('Linux system load','Current load (5 min)',43,34,0,0,300,0,'uptime | awk '{print $(NF-1)}' | tr -d ','','','','',6,2,0,'','','',0,0,1,0.00,0.00,'',0.00,0.00,'',0,'','linux','',0,0,0.000000000000000,'','nowizard','','','','',0,0,0,'','{\"going_unknown\":1}','',0,0,0,0,0,0,0,0,0,0); INSERT INTO `tnetwork_component` (`name`, `description`, `id_group`, `type`, `max`, `min`, `module_interval`, `tcp_port`, `tcp_send`, `tcp_rcv`, `snmp_community`, `snmp_oid`, `id_module_group`, `id_modulo`, `id_plugin`, `plugin_user`, `plugin_pass`, `plugin_parameter`, `max_timeout`, `max_retries`, `history_data`, `min_warning`, `max_warning`, `max_critical`, `str_warning`, `min_ff_event`, `min_critical`, `custom_string_2`, `str_critical`, `custom_integer_1`, `custom_string_1`, `post_process`, `custom_string_3`, `wizard_level`, `custom_integer_2`, `critical_instructions`, `unit`, `unknown_instructions`, `macros`, `warning_inverse`, `warning_instructions`, `tags`, `critical_inverse`, `module_macros`, `id_category`, `min_ff_event_warning`, `disabled_types_event`, `ff_type`, `min_ff_event_normal`, `dynamic_interval`, `min_ff_event_critical`, `dynamic_min`, `each_ff`, `dynamic_two_tailed`, `dynamic_max`, `dynamic_next`) VALUES ('Linux available memory percent','Available memory %',43,34,0,0,300,0,'free | grep Mem | awk '{print $NF/$2 * 100}'','','','',4,2,0,'','','',0,0,1,0.00,0.00,'',0.00,0.00,'',0,'','linux','',0,0,0.000000000000000,'%','nowizard','','','','',0,0,0,'','{\"going_unknown\":1}','',0,0,0,0,0,0,0,0,0,0); INSERT INTO `tnetwork_component` (`name`, `description`, `id_group`, `type`, `max`, `min`, `module_interval`, `tcp_port`, `tcp_send`, `tcp_rcv`, `snmp_community`, `snmp_oid`, `id_module_group`, `id_modulo`, `id_plugin`, `plugin_user`, `plugin_pass`, `plugin_parameter`, `max_timeout`, `max_retries`, `history_data`, `min_warning`, `max_warning`, `max_critical`, `str_warning`, `min_ff_event`, `min_critical`, `custom_string_2`, `str_critical`, `custom_integer_1`, `custom_string_1`, `post_process`, `custom_string_3`, `wizard_level`, `custom_integer_2`, `critical_instructions`, `unit`, `unknown_instructions`, `macros`, `warning_inverse`, `warning_instructions`, `tags`, `critical_inverse`, `module_macros`, `id_category`, `min_ff_event_warning`, `disabled_types_event`, `ff_type`, `min_ff_event_normal`, `dynamic_interval`, `min_ff_event_critical`, `dynamic_min`, `each_ff`, `dynamic_two_tailed`, `dynamic_max`, `dynamic_next`) VALUES ('Linux available disk /','Available free space in mountpoint /',43,34,0,0,300,0,'df / | tail -n +2 | awk '{print $(NF-1)}' | tr -d '%'','','','',4,2,0,'','','',0,0,1,0.00,0.00,'0.00',0.00,0.00,'',0,'','inherited','',0,0,0.000000000000000,'','nowizard','','nowizard','0','',0,0,0,'','{\"going_unknown\":1}','',0,0,0,0,0,0,0,0,0,0); + +-- +-- Dumping data for table `tpen` +-- + +INSERT IGNORE INTO `tpen` +VALUES + (9,'cisco','Cisco System'), + (11,'hp','Hewlett Packard'), + (2021,'general_snmp','U.C. Davis, ECE Dept. Tom'), + (2636,'juniper','Juniper Networks'), + (3375,'f5','F5 Labs'), + (8072,'general_snmp','Net SNMP'), + (12356,'fortinet','Fortinet') +; + +-- +-- Dumping data for table `tnetwork_profile` and `tnetwork_profile_pen` +-- + +SET @template_name = 'Network Management'; +SET @template_description = 'Basic network monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Network Management')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Cisco MIBS'; +SET @template_description = 'Cisco devices monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Cisco MIBS' OR g.name = 'Catalyst 2900')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 9)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Linux System'; +SET @template_description = 'Linux system monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); + +SET @module_group = 'Linux'; + +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Linux' OR g.name = 'UCD Mibs (Linux, UCD-SNMP)')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 2021 OR p.pen = 2636)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Windows System'; +SET @template_description = 'Windows system monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Microsoft Windows' OR g.name = 'Windows System')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Hardware'; +SET @template_description = 'Windows hardware monitoring templae (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Hardware Layer')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Active Directory'; +SET @template_description = 'Active directory monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows AD' OR g.name = 'AD Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows IIS'; +SET @template_description = 'IIS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows IIS' OR g.name = 'IIS services')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Exchange'; +SET @template_description = 'Exchange monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Exchange' OR g.name = 'Exchange Services' OR g.name = 'Exchange TCP Ports')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows LDAP'; +SET @template_description = 'LDAP monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows LDAP')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MDSTC'; +SET @template_description = 'MDSTC monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows MSDTC')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Printers'; +SET @template_description = 'Windows printers monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Printers')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows DNS'; +SET @template_description = 'Windows DNS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows DNS' OR g.name = 'DNS Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MS SQL Server'; +SET @template_description = 'MS SQL Server monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MS SQL Server')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Oracle'; +SET @template_description = 'Oracle monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Oracle')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'MySQL'; +SET @template_description = 'MySQL monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MySQL')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Antivirus'; +SET @template_description = 'Windows antivirus monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Norton' OR g.name = 'Panda' OR g.name = 'McAfee' OR g.name = 'Bitdefender' OR g.name = 'BullGuard' OR g.name = 'AVG' OR g.name = 'Kaspersky')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + + +-- Update widget. + +UPDATE twidget SET description='Show a visual console' WHERE class_name='MapsMadeByUser'; +UPDATE twidget SET description='Clock' WHERE class_name='ClockWidget'; +UPDATE twidget SET description='Group status' WHERE class_name='SystemGroupStatusWidget'; + + diff --git a/pandora_console/godmode/menu.php b/pandora_console/godmode/menu.php index b370bc2ac9..7a5295f1c5 100644 --- a/pandora_console/godmode/menu.php +++ b/pandora_console/godmode/menu.php @@ -137,11 +137,31 @@ if (!empty($sub)) { $sub = []; if (check_acl($config['id_user'], 0, 'PM')) { - $sub['godmode/modules/manage_network_components']['text'] = __('Network components'); - $sub['godmode/modules/manage_network_components']['id'] = 'Network components'; - enterprise_hook('components_submenu'); - $sub['godmode/modules/manage_network_templates']['text'] = __('Module templates'); - $sub['godmode/modules/manage_network_templates']['id'] = 'Module templates'; + // enterprise_hook('components_submenu'); + $sub['templates']['text'] = __('Templates'); + $sub['templates']['id'] = 'Templates'; + $sub['templates']['type'] = 'direct'; + $sub['templates']['subtype'] = 'nolink'; + $sub2 = []; + $sub2['godmode/modules/manage_module_templates']['text'] = __('Module templates'); + $sub2['godmode/modules/manage_module_templates']['id'] = 'Module templates'; + $sub2['godmode/modules/private_enterprise_numbers']['text'] = __('Private Enterprise Numbers'); + $sub2['godmode/modules/private_enterprise_numbers']['id'] = 'Private Enterprise Numbers'; + $sub2['enterprise/godmode/modules/local_components']['text'] = __('Local components'); + $sub2['enterprise/godmode/modules/local_components']['id'] = 'Local components'; + $sub2['godmode/modules/manage_network_components']['text'] = __('Remote components'); + $sub2['godmode/modules/manage_network_components']['id'] = 'Network components'; + $sub['templates']['sub2'] = $sub2; + /* + $sub2['godmode/modules/manage_snmp_modules']['text'] = __('SNMP Modules'); + $sub2['godmode/modules/manage_snmp_modules']['id'] = 'SNMP Modules'; + $sub2['godmode/modules/manage_wmi_modules']['text'] = __('WMI Modules'); + $sub2['godmode/modules/manage_wmi_modules']['id'] = 'WMI Modules'; + $sub['godmode/modules/manage_block_templates']['text'] = __('Module blocks'); + $sub['godmode/modules/manage_block_templates']['id'] = 'Module blocks'; + */ + + enterprise_hook('inventory_submenu'); enterprise_hook('autoconfiguration_menu'); enterprise_hook('agent_repository_menu'); diff --git a/pandora_console/godmode/modules/configuration_wizard_setup.php b/pandora_console/godmode/modules/configuration_wizard_setup.php new file mode 100644 index 0000000000..ccf5ef04ca --- /dev/null +++ b/pandora_console/godmode/modules/configuration_wizard_setup.php @@ -0,0 +1,35 @@ + '[ModuleTemplates]'.$e->getMessage() ]); + exit; + } else { + echo '[ModuleTemplates]'.$e->getMessage(); + } + + // Stop this execution, but continue 'globally'. + return; +} + +// AJAX controller. +if (is_ajax()) { + $method = get_parameter('method'); + + if (method_exists($obj, $method) === true) { + $obj->{$method}(); + } else { + $obj->error('Method not found. ['.$method.']'); + } + + // Stop any execution. + exit; +} else { + // Run. + $obj->run(); +} diff --git a/pandora_console/godmode/modules/manage_network_components.php b/pandora_console/godmode/modules/manage_network_components.php index afd7c09189..baa626f1ec 100644 --- a/pandora_console/godmode/modules/manage_network_components.php +++ b/pandora_console/godmode/modules/manage_network_components.php @@ -66,7 +66,7 @@ if (defined('METACONSOLE')) { } ui_print_page_header( - __('Module management').' » '.__('Network component management'), + __('Module management').' » '.__('Remote component management'), '', false, $help_header, diff --git a/pandora_console/godmode/modules/manage_network_templates.php b/pandora_console/godmode/modules/manage_network_templates.php index eebf408caa..2050fb916c 100644 --- a/pandora_console/godmode/modules/manage_network_templates.php +++ b/pandora_console/godmode/modules/manage_network_templates.php @@ -45,8 +45,15 @@ ui_print_page_header( true, 'modulemodal' ); - - +/* + // At this moment, this message is not necessary + ui_print_info_message( + __( + 'This section is maintained only for legacy use. Please, keep in mind use %s for manage template blocks.', + 'Module Blocks' + ) + ); +*/ require_once 'include/functions_network_profiles.php'; $delete_profile = (bool) get_parameter('delete_profile'); diff --git a/pandora_console/godmode/modules/private_enterprise_numbers.php b/pandora_console/godmode/modules/private_enterprise_numbers.php new file mode 100644 index 0000000000..ca6add6640 --- /dev/null +++ b/pandora_console/godmode/modules/private_enterprise_numbers.php @@ -0,0 +1,68 @@ + '[ConfigPEN]'.$e->getMessage() ]); + exit; + } else { + echo '[ConfigPEN]'.$e->getMessage(); + } + + // Stop this execution, but continue 'globally'. + return; +} + +// AJAX controller. +if (is_ajax()) { + $method = get_parameter('method'); + + if (method_exists($obj, $method) === true) { + $obj->{$method}(); + } else { + $obj->error('Method not found. ['.$method.']'); + } + + // Stop any execution. + exit; +} else { + // Run. + $obj->run(); +} diff --git a/pandora_console/godmode/servers/discovery.php b/pandora_console/godmode/servers/discovery.php index 7215ee7dfb..3dd8e258ee 100755 --- a/pandora_console/godmode/servers/discovery.php +++ b/pandora_console/godmode/servers/discovery.php @@ -1,5 +1,7 @@ run(); - if (is_array($result) === true) { - // Redirect control and messages to DiscoveryTasklist. - $classname_selected = 'DiscoveryTaskList'; - $wiz = new $classname_selected($page); - $result = $wiz->run($result['msg'], $result['result']); + $wiz = new $classname_selected((int) $page); + + // AJAX controller. + if (is_ajax()) { + $method = get_parameter('method'); + + if (method_exists($wiz, $method) === true) { + $wiz->{$method}(); + } else { + $wiz->error('Method not found. ['.$method.']'); + } + + // Stop any execution. + exit; + } else { + $result = $wiz->run(); + if (is_array($result) === true) { + // Redirect control and messages to DiscoveryTasklist. + $classname_selected = 'DiscoveryTaskList'; + $wiz = new $classname_selected($page); + $result = $wiz->run($result['msg'], $result['result']); + } } } diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php index f87b2a563e..118f604b14 100644 --- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php +++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php @@ -26,7 +26,9 @@ * ============================================================================ */ -require_once __DIR__.'/Wizard.main.php'; +global $config; + +require_once $config['homedir'].'/include/class/HTML.class.php'; require_once $config['homedir'].'/include/functions_users.php'; require_once $config['homedir'].'/include/functions_reports.php'; require_once $config['homedir'].'/include/functions_cron.php'; @@ -34,11 +36,13 @@ enterprise_include_once('include/functions_tasklist.php'); enterprise_include_once('include/functions_cron.php'); ui_require_css_file('task_list'); +ui_require_css_file('simTree'); +ui_require_javascript_file('simTree'); /** * Defined as wizard to guide user to explore running tasks. */ -class DiscoveryTaskList extends Wizard +class DiscoveryTaskList extends HTML { @@ -119,8 +123,9 @@ class DiscoveryTaskList extends Wizard } $force_run = (bool) get_parameter('force_run'); - if ($force_run === true) { - return $this->forceConsoleTask(); + $force = (bool) get_parameter('force'); + if ($force_run === true || $force === true) { + return $this->forceTask(); } $delete_console_task = (bool) get_parameter('delete_console_task'); @@ -163,6 +168,16 @@ class DiscoveryTaskList extends Wizard 'attributes' => 'class="sub cancel"', 'return' => true, ], + ],[ + 'class' => 'action-buttons rule-builder-actions', + 'arguments' => [ + 'name' => 'refresh', + 'label' => __('Refresh'), + 'type' => 'button', + 'attributes' => 'class="sub upd"', + 'return' => true, + 'script' => 'location.reload();', + ], ], ], ]; @@ -237,7 +252,7 @@ class DiscoveryTaskList extends Wizard * * @return void */ - public function forceConsoleTask() + public function forceTask() { global $config; @@ -252,12 +267,46 @@ class DiscoveryTaskList extends Wizard $id_console_task = (int) get_parameter('id_console_task'); - if ($id_console_task !== null) { + if ($id_console_task != null) { + // -------------------------------- + // FORCE A CONSOLE TASK + // -------------------------------- enterprise_hook('cron_task_run', [$id_console_task, true]); // Trick to avoid double execution. header('Location: '.$this->url); - } + } else { + // -------------------------------- + // FORCE A RECON TASK + // -------------------------------- + if (check_acl($config['id_user'], 0, 'AW')) { + if (isset($_GET['force'])) { + $id = (int) get_parameter_get('force', 0); + // Schedule execution. + $review_mode = db_get_value( + 'review_mode', + 'trecon_task', + 'id_rt', + $id + ); + if ($review_mode != DISCOVERY_STANDARD) { + // Force re-scan for supervised tasks. + $review_mode = DISCOVERY_REVIEW; + } + + db_process_sql_update( + 'trecon_task', + [ + 'utimestamp' => 0, + 'status' => 1, + 'review_mode' => $review_mode, + ], + ['id_rt' => $id] + ); + header('Location: '.$this->url); + } + } + } } @@ -330,28 +379,7 @@ class DiscoveryTaskList extends Wizard include_once $config['homedir'].'/include/functions_servers.php'; include_once $config['homedir'].'/include/functions_network_profiles.php'; - $modules_server = 0; - $total_modules = 0; - $total_modules_data = 0; - - // -------------------------------- - // FORCE A RECON TASK - // -------------------------------- - if (check_acl($config['id_user'], 0, 'AW')) { - if (isset($_GET['force'])) { - $id = (int) get_parameter_get('force', 0); - servers_force_recon_task($id); - header( - 'Location: '.ui_get_full_url( - 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=tasklist' - ) - ); - } - } - $recon_tasks = db_get_all_rows_sql('SELECT * FROM trecon_task'); - $user_groups = implode(',', array_keys(users_get_groups())); - // Show network tasks for Recon Server. if ($recon_tasks === false) { $recon_tasks = []; @@ -368,18 +396,22 @@ class DiscoveryTaskList extends Wizard $table->data = []; $table->align = []; $table->headstyle = []; + $table->style = []; + $table->style[4] = 'word-break: break-word;'; for ($i = 0; $i < 9; $i++) { $table->headstyle[$i] = 'text-align: left;'; } + // Name. + $table->headstyle[4] .= 'min-width: 100px; width: 600px;'; // Status. - $table->headstyle[5] .= 'min-width: 100px; width: 100px;'; + $table->headstyle[5] .= 'min-width: 50px; width: 100px;'; // Task type. - $table->headstyle[6] .= 'min-width: 200px; width: 150px;'; + $table->headstyle[6] .= 'min-width: 150px; width: 150px;'; // Progress. - $table->headstyle[7] .= 'min-width: 150px; width: 150px;'; + $table->headstyle[7] .= 'min-width: 50px; width: 150px;'; // Updated at. - $table->headstyle[8] .= 'min-width: 150px; width: 150px;'; + $table->headstyle[8] .= 'min-width: 50px; width: 150px;'; // Operations. $table->headstyle[9] .= 'min-width: 150px; width: 150px;'; @@ -454,11 +486,20 @@ class DiscoveryTaskList extends Wizard if ($task['disabled'] == 0 && $server_name !== '') { if (check_acl($config['id_user'], 0, 'AW')) { - $data[0] = ''; + ); + $data[0] .= '\''; + if ($task['type'] == DISCOVERY_HOSTDEVICES) { + $title = __('Are you sure?'); + $message = 'This action will rescan the target networks.'; + $data[0] .= ', {title: \''.$title.'\', message: \''.$message.'\'}'; + } + + $data[0] .= ');" >'; $data[0] .= html_print_image('images/target.png', true, ['title' => __('Force')]); - $data[0] .= ''; + $data[0] .= ''; } } else if ($task['disabled'] == 2) { $data[0] = ui_print_help_tip( @@ -472,12 +513,12 @@ class DiscoveryTaskList extends Wizard // Name task. $data[1] = ''; if ($task['disabled'] != 2) { - $data[1] .= ''; + $data[1] .= ''; } $data[1] .= ''.$task['name'].''; if ($task['disabled'] != 2) { - $data[1] .= ''; + $data[1] .= ''; } $data[2] = $server_name; @@ -496,10 +537,38 @@ class DiscoveryTaskList extends Wizard $data[4] = '-'; } - if ($task['status'] <= 0) { - $data[5] = __('Done'); + $can_be_reviewed = false; + if ($task['review_mode'] == DISCOVERY_STANDARD) { + if ($task['status'] <= 0 + && empty($task['summary']) === false + ) { + $data[5] = __('Done'); + } else if ($task['utimestamp'] == 0 + && empty($task['summary']) + ) { + $data[5] = __('Not started'); + } else { + $data[5] = __('Pending'); + } } else { - $data[5] = __('Pending'); + if ($task['status'] <= 0 + && empty($task['summary']) === false + ) { + $can_be_reviewed = true; + $data[5] = ''; + $data[5] .= __('Review'); + $data[5] .= ''; + } else if ($task['utimestamp'] == 0 + && empty($task['summary']) + ) { + $data[5] = __('Not started'); + } else { + if ($task['review_mode'] == DISCOVERY_RESULTS) { + $data[5] = __('Processing'); + } else { + $data[5] = __('Searching'); + } + } } switch ($task['type']) { @@ -573,14 +642,7 @@ class DiscoveryTaskList extends Wizard true, ['title' => __('Discovery NetScan')] ).'  '; - $str = network_profiles_get_name( - $task['id_network_profile'] - ); - if (!empty($str)) { - $data[6] .= $str; - } else { - $data[6] .= __('Discovery.NetScan'); - } + $data[6] .= __('Discovery.NetScan'); } else { // APP or external script recon task. $data[6] = html_print_image( @@ -595,7 +657,28 @@ class DiscoveryTaskList extends Wizard if ($task['status'] <= 0 || $task['status'] > 100) { $data[7] = '-'; } else { - $data[7] = ui_progress($task['status'], '100%', 1.5); + $data[7] = ui_progress( + $task['status'], + '100%', + 1.9, + // Color. + '#82b92e', + // Return. + true, + // Text. + '', + // Ajax. + [ + 'page' => 'godmode/servers/discovery', + 'interval' => 10, + 'simple' => 1, + 'data' => [ + 'wiz' => 'tasklist', + 'id' => $task['id_rt'], + 'method' => 'taskProgress', + ], + ] + ); } if ($task['utimestamp'] > 0) { @@ -609,10 +692,22 @@ class DiscoveryTaskList extends Wizard if (!$no_operations) { if ($task['disabled'] != 2) { - $data[9] = ''; + $data[9] = ''; + if ($can_be_reviewed) { + $data[9] .= ''; + $data[9] .= html_print_image( + 'images/expand.png', + true, + ['title' => __('Review results')] + ); + $data[9] .= ''; + } + + $data[9] .= ''; $data[9] .= html_print_image( 'images/eye.png', - true + true, + ['title' => __('View summary')] ); $data[9] .= ''; } @@ -623,10 +718,11 @@ class DiscoveryTaskList extends Wizard && $task['type'] != DISCOVERY_CLOUD_AWS_RDS ) { if (check_acl($config['id_user'], 0, 'MR')) { - $data[9] .= ''; + $data[9] .= ''; $data[9] .= html_print_image( 'images/dynamic_network_icon.png', - true + true, + ['title' => __('View map')] ); $data[9] .= ''; } @@ -646,13 +742,15 @@ class DiscoveryTaskList extends Wizard ) ).'">'.html_print_image( 'images/config.png', - true + true, + ['title' => __('Edit task')] ).''; $data[9] .= ''.html_print_image( 'images/cross.png', - true + true, + ['title' => __('Delete task')] ).''; } else { // Check if is a H&D, Cloud or Application or IPAM. @@ -664,13 +762,15 @@ class DiscoveryTaskList extends Wizard ) ).'">'.html_print_image( 'images/config.png', - true + true, + ['title' => __('Edit task')] ).''; $data[9] .= ''.html_print_image( 'images/cross.png', - true + true, + ['title' => __('Delete task')] ).''; } } else { @@ -700,9 +800,15 @@ class DiscoveryTaskList extends Wizard // Div neccesary for modal map task. echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; unset($table); + ui_require_javascript_file('pandora_ui'); ui_require_javascript_file('pandora_taskList'); return $return; @@ -787,4 +893,633 @@ class DiscoveryTaskList extends Wizard } + /** + * Returns percent of completion of target task. + * + * @return void + */ + public function taskProgress() + { + if (!is_ajax()) { + echo json_encode(['error' => true]); + return; + } + + $id_task = get_parameter('id', 0); + + if ($id_task <= 0) { + echo json_encode(['error' => true]); + return; + } + + $status = db_get_value('status', 'trecon_task', 'id_rt', $id_task); + if ($status < 0) { + $status = 100; + } + + echo json_encode($status); + } + + + /** + * Generates charts for progress popup. + * + * @param array $task Task. + * + * @return string Charts in HTML. + */ + private function progressTaskGraph($task) + { + $result .= '
'; + $result .= '
'; + $result .= ''._('Overall Progress').''; + + $result .= '
'; + $result .= progress_circular_bar( + $task['id_rt'], + ($task['status'] < 0) ? 100 : $task['status'], + 200, + 200, + '#7eb641', + '%', + '', + '#3A3A3A', + 0 + ); + + $result .= '
'; + if ($task['status'] > 0) { + switch ($task['stats']['step']) { + case STEP_SCANNING: + $str = __('Scanning network'); + break; + + case STEP_CAPABILITIES: + $str = __('Checking'); + break; + + case STEP_AFT: + $str = __('Finding AFT connectivity'); + break; + + case STEP_TRACEROUTE: + $str = __('Finding traceroute connectivity'); + break; + + case STEP_GATEWAY: + $str = __('Finding gateway connectivity'); + break; + + case STEP_STATISTICS: + $str = __('Searching for devices...'); + break; + + case STEP_APP_SCAN: + $str = __('Analyzing application...'); + break; + + case STEP_CUSTOM_QUERIES: + $str = __('Executing custom queries...'); + break; + + case STEP_MONITORING: + $str = __('Testing modules...'); + break; + + case STEP_PROCESSING: + $str = __('Processing results...'); + break; + + default: + $str = __('Processing...'); + break; + } + + $result .= '
'; + $result .= '
'; + $result .= ''.$str.' '; + if (empty($str) === false) { + $result .= $task['stats']['c_network_name']; + } + + $result .= ''; + + $result .= '
'; + $result .= progress_circular_bar( + $task['id_rt'].'_detail', + $task['stats']['c_network_percent'], + 200, + 200, + '#7eb641', + '%', + '', + '#3A3A3A', + 0 + ); + $result .= '
'; + } + + if ($task['review_mode'] == DISCOVERY_REVIEW) { + if ($task['status'] <= 0 + && empty($task['summary']) === false + ) { + $result .= ''; + $result .= '»'.__('Review'); + $result .= ''; + } + } + + $result .= '
'; + + return $result; + } + + + /** + * Generates a summary table for given task. + * + * @param array $task Task. + * + * @return html code with summary. + */ + private function progressTaskSummary($task) + { + global $config; + include_once $config['homedir'].'/include/graphs/functions_d3.php'; + + if (is_array($task) === false) { + return ''; + } + + $output = ''; + + if (is_array($task['stats']) === false) { + $task['stats'] = json_decode($task['summary'], true); + } + + if (is_array($task['stats'])) { + $i = 0; + $table = new StdClasS(); + $table->class = 'databox data'; + $table->width = '75%'; + $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; + $table->rowid = []; + $table->data = []; + + if ($task['review_mode'] == DISCOVERY_RESULTS) { + $agents_review = db_get_all_rows_filter( + 'tdiscovery_tmp_agents', + ['id_rt' => $task['id_rt']] + ); + + $agents = 0; + $total = 0; + if (is_array($agents_review)) { + foreach ($agents_review as $agent) { + $data = json_decode(base64_decode($agent['data']), true); + + if (is_array($data) === false) { + continue; + } + + if (is_array($data['agent']) === false) { + continue; + } + + // Ensure agent_id really exists. + $agent_id = agents_get_agent_id( + $data['agent']['nombre'], + true + ); + + if ($agent_id > 0) { + $agents++; + } + + $total++; + } + } + + // Content. + $table->data[$i][0] = ''.__('Host&devices total').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $total; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Agents monitored').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $agents; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Agents pending').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= ($total - $agents); + $table->data[$i++][1] .= ''; + } else { + // Content. + $table->data[$i][0] = ''.__('Hosts discovered').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $task['stats']['summary']['discovered']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Alive').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $task['stats']['summary']['alive']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Not alive').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $task['stats']['summary']['not_alive']; + $table->data[$i++][1] .= ''; + + if ($task['type'] == DISCOVERY_HOSTDEVICES) { + $table->data[$i][0] = ''.__('Responding SNMP').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $task['stats']['summary']['SNMP']; + $table->data[$i++][1] .= ''; + + $table->data[$i][0] = ''.__('Responding WMI').''; + $table->data[$i][1] = ''; + $table->data[$i][1] .= $task['stats']['summary']['WMI']; + $table->data[$i++][1] .= ''; + } + } + + $output = '
'.__('Summary').'
'; + $output .= html_print_table($table, true).''; + } + + return $output; + } + + + /** + * Content of modal 'task progress', ajax only. + * + * @return void + */ + public function progressTaskDiscovery() + { + if (!is_ajax()) { + return; + } + + $id_task = get_parameter('id', 0); + + if ($id_task <= 0) { + echo json_encode(['error' => true]); + return; + } + + $task = db_get_row('trecon_task', 'id_rt', $id_task); + $task['stats'] = json_decode($task['summary'], true); + $summary = $this->progressTaskSummary($task); + + $output = ''; + + // Header information. + if ((int) $task['status'] <= 0 && empty($summary)) { + $output .= ui_print_info_message( + __('This task has never executed'), + '', + true + ); + } else if ($task['status'] == 1 + || ($task['utimestamp'] == 0 && $task['interval_sweep']) + ) { + $output .= ui_print_info_message( + __('Task queued, please wait.'), + '', + true + ).''; + } else { + $output .= $this->progressTaskGraph($task); + } + + $output .= $summary; + + echo json_encode(['html' => $output]); + } + + + /** + * Get a map of target task. + * + * @return void + */ + public function taskShowmap() + { + global $config; + include_once $config['homedir'].'/include/class/NetworkMap.class.php'; + $id_task = get_parameter('id', 0); + + $map = new NetworkMap( + [ + 'id_task' => $id_task, + 'pure' => 1, + 'widget' => true, + 'map_options' => [ + 'map_filter' => [ + 'x_offs' => 120, + 'node_sep' => 10, + ], + ], + ] + ); + $map->printMap(); + } + + + /** + * Shows a modal to review results found by discovery task. + * + * @return void + */ + public function showTaskReview() + { + $id_task = get_parameter('id', 0); + if ($id_task <= 0) { + ui_print_error_message(__('Invalid task')); + return; + } + + $task_data = db_get_all_rows_filter( + 'tdiscovery_tmp_agents', + ['id_rt' => $id_task] + ); + $task = db_get_row('trecon_task', 'id_rt', $id_task); + + $simple_data = []; + if (is_array($task_data)) { + foreach ($task_data as $agent) { + $data = json_decode(base64_decode($agent['data']), true); + if (is_array($data) === false) { + continue; + } + + if (is_array($data['agent']) === false) { + continue; + } + + $id = $data['agent']['nombre']; + + // Partial. + $tmp = [ + 'id' => $id, + 'name' => $id, + 'checked' => $data['agent']['checked'], + ]; + + // Ensure agent_id really exists. + $agent_id = agents_get_agent_id($data['agent']['nombre'], true); + + if ($agent_id > 0) { + $tmp['disabled'] = 1; + $tmp['agent_id'] = $agent_id; + $tmp['checked'] = 1; + } + + // Store. + $simple_data[] = $tmp; + + if (is_array($data['modules'])) { + $simple_data = array_merge( + $simple_data, + array_reduce( + $data['modules'], + function ($carry, $item) use ($id, $agent_id) { + if (empty($item['name'])) { + $item['name'] = $item['nombre']; + } + + if ($item['name'] == 'Host Alive') { + return $carry; + } + + if (empty($item['name'])) { + $item['name'] = $item['nombre']; + } + + $tmp = [ + 'name' => $item['name'], + 'id' => $id.'-'.$item['name'], + 'pid' => $id, + 'checked' => $item['checked'], + ]; + + $agentmodule_id = modules_get_agentmodule_id( + io_safe_input($item['name']), + $agent_id + ); + + if ($agentmodule_id > 0) { + $tmp['disabled'] = 1; + $tmp['checked'] = 1; + $tmp['module_id'] = $agentmodule_id; + } + + $carry[] = $tmp; + return $carry; + }, + [] + ) + ); + } + } + } + + echo '
'; + echo $this->progressTaskSummary($task); + echo '
'; + + if (count($simple_data) > 0) { + echo '
'; + echo ''; + echo __('Please select devices to be monitored'); + echo '
'; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo parent::printTree( + 'tree', + $simple_data + ); + echo '
'; + } else { + echo '
'; + echo ''; + echo __('No devices found in temporary resources, please re-launch.'); + echo ''; + echo '
'; + } + + } + + + /** + * Processes a review over temporary results found by discovery task. + * + * @return void + */ + public function parseTaskReview() + { + $id_task = get_parameter('id', 0); + if ($id_task <= 0) { + echo $this->error(__('Invalid task')); + return; + } + + $ids = []; + $n_agents = 0; + $selection = io_safe_output(get_parameter('tree-data-tree', '')); + if (empty($selection) === false) { + $selection = json_decode($selection, true); + $ids = array_reduce( + $selection, + function ($carry, $item) use (&$n_agents) { + // String is agent-module. + $fields = explode('-', $item['id']); + $agent_name = $fields[0]; + $module_name = $fields[1]; + if ($module_name === null) { + // Do not count if already created. + if (db_get_value( + 'id_agente', + 'tagente', + 'nombre', + io_safe_input($agent_name) + ) === false + ) { + $n_agents++; + } + } + + $carry[] = $item['id']; + return $carry; + } + ); + } + + $task_data = db_get_all_rows_filter( + 'tdiscovery_tmp_agents', + ['id_rt' => $id_task] + ); + + // License precheck. + $license = enterprise_hook('license_get_info'); + + if (is_array($license) === true + && $n_agents > ($license['limit'] - $license['count']) + ) { + $limit = ($license['limit'] - $license['count']); + echo json_encode( + [ + 'error' => __( + 'Your selection exceeds the agents available on your license. Limit %d', + $limit + ), + ] + ); + return; + } + + $summary = []; + if (is_array($ids)) { + foreach ($task_data as $row) { + $data = json_decode(base64_decode($row['data']), true); + + if (is_array($data)) { + // Analize each agent. + $agent_name = $data['agent']['nombre']; + if (in_array($agent_name, $ids)) { + if ($data['agent']['checked'] != 1) { + $summary[] = '
  • '.$agent_name.'
  • '; + } + + $data['agent']['checked'] = 1; + } else { + if ($data['agent']['checked'] == 1) { + $summary[] = '
  • '.__('Removed').' '.$agent_name.'
  • '; + } + + $data['agent']['checked'] = 0; + } + + // Modules. + if (is_array($data['modules'])) { + $n_modules = count($data['modules']); + foreach ($data['modules'] as $module_name => $module) { + if (in_array($agent_name.'-'.$module_name, $ids)) { + if ($data['modules'][$module_name]['checked'] != 1) { + $summary[] = '
  • '.$agent_name.' - '.$module_name.'
  • '; + } + + $data['modules'][$module_name]['checked'] = 1; + } else { + if ($data['modules'][$module_name]['checked'] == 1) { + if ($module_name != 'Host Alive') { + $summary[] = '
  • '.__('Removed').' '.$agent_name.' - '.$module_name.'
  • '; + } + } + + $data['modules'][$module_name]['checked'] = 0; + } + } + } + + // Update data. + db_process_sql_update( + 'tdiscovery_tmp_agents', + [ + 'data' => base64_encode(json_encode($data)), + 'review_date' => date('Y-m-d H:i:s'), + ], + [ + 'id_rt' => $id_task, + 'label' => $agent_name, + ] + ); + } + } + } + + // Schedule execution. + db_process_sql_update( + 'trecon_task', + [ + 'utimestamp' => 0, + 'status' => 1, + 'review_mode' => DISCOVERY_RESULTS, + ], + ['id_rt' => $id_task] + ); + + if (empty($summary)) { + $out .= __('No changes. Re-Scheduled'); + } else { + $out .= __('Scheduled for creation'); + $out .= ''; + } + + echo json_encode( + ['result' => $out] + ); + } + + } diff --git a/pandora_console/godmode/wizards/HostDevices.class.php b/pandora_console/godmode/wizards/HostDevices.class.php index fd7811f2e9..5f6f0c7dba 100755 --- a/pandora_console/godmode/wizards/HostDevices.class.php +++ b/pandora_console/godmode/wizards/HostDevices.class.php @@ -1,6 +1,6 @@ page == 0) { // Check if we're updating a task. $task_id = get_parameter('task', null); @@ -297,9 +300,63 @@ class HostDevices extends Wizard $comment = get_parameter('comment', ''); $server_id = get_parameter('id_recon_server', ''); $network = get_parameter('network', ''); + $network_csv_enabled = (bool) get_parameter_switch( + 'network_csv_enabled', + false + ); $id_group = get_parameter('id_group', ''); $interval = get_parameter('interval', 0); + if ($network_csv_enabled) { + if (empty($_FILES['network_csv']['type']) === false) { + if ($_FILES['network_csv']['type'] != 'text/csv' + && $_FILES['network_csv']['type'] != 'text/plain' + && $_FILES['network_csv']['type'] != 'application/octet-stream' + && $_FILES['network_csv']['type'] != 'application/vnd.ms-excel' + && $_FILES['network_csv']['type'] != 'text/x-csv' + && $_FILES['network_csv']['type'] != 'application/csv' + && $_FILES['network_csv']['type'] != 'application/x-csv' + && $_FILES['network_csv']['type'] != 'text/csv' + && $_FILES['network_csv']['type'] != 'text/comma-separated-values' + && $_FILES['network_csv']['type'] != 'text/x-comma-separated-values' + && $_FILES['network_csv']['type'] != 'text/tab-separated-values' + ) { + $this->msg = __( + 'Invalid mimetype for csv file: %s', + $_FILES['network_csv']['type'] + ); + return false; + } + + $network = preg_split( + "/\n|,|;/", + trim( + file_get_contents( + $_FILES['network_csv']['tmp_name'] + ) + ) + ); + unlink($_FILES['network_csv']['tmp_name']); + if (empty($network) || is_array($network) === false) { + $this->msg = __( + 'Invalid content readed from csv file: %s', + $_FILES['network_csv']['name'] + ); + return false; + } + + // Sanitize. + $network = array_unique($network); + $network = array_filter( + $network, + function ($item) { + return (!empty($item)); + } + ); + $network = join(',', $network); + } + } + if (isset($task_id) === true) { // We're updating this task. $task = db_get_row( @@ -333,18 +390,15 @@ class HostDevices extends Wizard if ($task_id !== null && $taskname == null && $server_id == null - && $id_group == null - && $server == null - && $datacenter == '' - && $user == '' - && $pass == '' - && $encrypt == null - && $interval == 0 + && empty($id_group) === true + && empty($network) === true + && empty($network_csv) === true + && $interval === 0 ) { // Default values, no data received. // User is accesing directly to this page. if (check_acl( - $config['id_usuario'], + $config['id_user'], $this->task['id_group'], $this->access ) != true @@ -386,6 +440,7 @@ class HostDevices extends Wizard $this->task['id_recon_server'] = $server_id; $this->task['id_group'] = $id_group; $this->task['interval_sweep'] = $interval; + $this->task['subnet_csv'] = $network_csv_enabled; if (isset($this->task['id_rt']) === false) { // Create. @@ -423,7 +478,10 @@ class HostDevices extends Wizard return false; } - $id_network_profile = get_parameter('id_network_profile', null); + $id_network_profile = get_parameter('id_network_profile', []); + $review_results = get_parameter_switch('review_results'); + $review_limited = (bool) get_parameter('review_limited', 0); + $auto_monitor = get_parameter_switch('auto_monitor'); $autoconf_enabled = get_parameter_switch( 'autoconfiguration_enabled' ); @@ -443,7 +501,7 @@ class HostDevices extends Wizard $snmp_privacy_pass = get_parameter('snmp_privacy_pass', null); $snmp_auth_method = get_parameter('snmp_auth_method', null); $snmp_security_level = get_parameter('snmp_security_level', null); - $auth_strings = get_parameter('auth_strings', null); + $auth_strings = get_parameter('auth_strings', []); if ($snmp_version == 3) { $this->task['snmp_community'] = $snmp_context; @@ -452,7 +510,28 @@ class HostDevices extends Wizard } $this->task['autoconfiguration_enabled'] = $autoconf_enabled; - $this->task['id_network_profile'] = $id_network_profile; + $this->task['id_network_profile'] = ''; + if (is_array($id_network_profile) === true) { + $this->task['id_network_profile'] = join( + ',', + $id_network_profile + ); + } + + if ($review_limited === true) { + // License limited, force review. + $this->task['review_mode'] = DISCOVERY_REVIEW; + } else { + if ($review_results) { + if ($this->task['review_mode'] != DISCOVERY_RESULTS) { + $this->task['review_mode'] = DISCOVERY_REVIEW; + } + } else { + $this->task['review_mode'] = DISCOVERY_STANDARD; + } + } + + $this->task['auto_monitor'] = $auto_monitor; $this->task['snmp_enabled'] = $snmp_enabled; $this->task['os_detect'] = $os_detect; $this->task['parent_detection'] = $parent_detection; @@ -467,7 +546,13 @@ class HostDevices extends Wizard $this->task['snmp_privacy_pass'] = $snmp_privacy_pass; $this->task['snmp_auth_method'] = $snmp_auth_method; $this->task['snmp_security_level'] = $snmp_security_level; - $this->task['auth_strings'] = $auth_strings; + $this->task['auth_strings'] = ''; + if (is_array($auth_strings) === true) { + $this->task['auth_strings'] = join( + ',', + $auth_strings + ); + } if ($this->task['disabled'] == 2) { // Wizard finished. @@ -562,7 +647,7 @@ class HostDevices extends Wizard // Check ACL. If user is not able to manage target task, // redirect him to main page. if (check_acl( - $config['id_usuario'], + $config['id_user'], $this->task['id_group'], $this->access ) != true @@ -598,10 +683,21 @@ class HostDevices extends Wizard } if ($this->page < $this->maxPagesNetScan) { + $title = __('NetScan'); + + if ($this->page == 1) { + $title = __( + '"%s" features', + io_safe_output( + $this->task['name'] + ) + ); + } + // Avoid to print header out of wizard. $this->prepareBreadcrum($breadcrum); ui_print_page_header( - __('NetScan'), + $title, '', false, '', @@ -678,7 +774,7 @@ class HostDevices extends Wizard $form['rows'][0]['columns'][0] = [ 'width' => '30%', - 'style' => 'padding: 9px;', + 'style' => 'padding: 9px;min-width: 250px;', 'inputs' => [ '0' => [ 'arguments' => [ @@ -705,7 +801,10 @@ class HostDevices extends Wizard 'name' => 'interval_manual_defined', 'return' => true, ], - 'extra' => ''.html_print_extended_select_for_time( + 'extra' => '
    '.ui_print_help_tip( + __('The minimum recomended interval for Recon Task is 5 minutes'), + true + ).html_print_extended_select_for_time( 'interval', $this->task['interval_sweep'], '', @@ -715,10 +814,7 @@ class HostDevices extends Wizard true, false, false - ).ui_print_help_tip( - __('The minimum recomended interval for Recon Task is 5 minutes'), - true - ).'', + ).'
    ', ], ], @@ -728,6 +824,7 @@ class HostDevices extends Wizard 'width' => '40%', 'padding-right' => '12%', 'padding-left' => '5%', + 'style' => 'min-width: 350px', 'inputs' => [ '0' => [ 'label' => ''.__('Task name').':', @@ -760,6 +857,54 @@ class HostDevices extends Wizard ], ], '2' => [ + 'label' => ''.__('Use CSV file definition').':'.ui_print_help_tip( + __('Define targets using csv o network definition.'), + true + ), + 'class' => 'no-margin', + 'arguments' => [ + 'name' => 'network_csv_enabled', + 'value' => $this->task['subnet_csv'], + 'type' => 'switch', + 'inline' => true, + 'class' => 'discovery_full_width_input', + 'onclick' => 'toggleNetwork(this);', + ], + ], + '3' => [ + 'hidden' => (($this->task['subnet_csv'] == '1') ? 0 : 1), + 'block_id' => 'csv_subnet', + 'block_content' => [ + [ + 'label' => ''.__('Networks (csv)').':'.ui_print_help_tip( + __('You can upload a CSV file. Each line must contain a network in IP/MASK format. For instance: 192.168.1.1/32'), + true + ), + 'arguments' => [ + 'name' => 'network_csv', + 'type' => 'file', + 'columns' => 25, + 'rows' => 10, + 'class' => 'discovery_full_width_input', + ], + ], + [ + 'label' => ''.__('Networks (current)').':'.ui_print_help_tip( + __('Plese upload a new file to overwrite this content.'), + true + ), + 'arguments' => [ + 'attributes' => 'readonly', + 'type' => 'textarea', + 'size' => 25, + 'value' => $this->task['subnet'], + ], + ], + ], + ], + '4' => [ + 'hidden' => (($this->task['subnet_csv'] == '1') ? 1 : 0), + 'id' => 'std_subnet', 'label' => ''.__('Network').':'.ui_print_help_tip( __('You can specify several networks, separated by commas, for example: 192.168.50.0/24,192.168.60.0/24'), true @@ -794,6 +939,7 @@ class HostDevices extends Wizard $form['rows'][0]['columns'][2] = [ 'width' => '30%', + 'style' => 'min-width: 250px', 'inputs' => ['0' => $group_select], ]; @@ -823,8 +969,9 @@ class HostDevices extends Wizard } $form['form'] = [ - 'method' => 'POST', - 'action' => $this->url.'&mode=netscan&page='.($this->page + 1).$task_url, + 'method' => 'POST', + 'enctype' => 'multipart/form-data', + 'action' => $this->url.'&mode=netscan&page='.($this->page + 1).$task_url, ]; // Default. @@ -848,7 +995,19 @@ class HostDevices extends Wizard $("#hidden-interval").val('.$interval.'); $("#interval_units").val('.$unit.'); } - }).change();'; + }).change(); + + function toggleNetwork(e) { + if (e.checked) { + $(\'#csv_subnet\').removeClass("hidden"); + $(\'#std_subnet\').addClass("hidden"); + } else { + $(\'#csv_subnet\').addClass("hidden"); + $(\'#std_subnet\').removeClass("hidden"); + } + }; + + '; $this->printFormAsGrid($form); $this->printGoBackButton($this->url.'&page='.($this->page - 1)); @@ -878,21 +1037,101 @@ class HostDevices extends Wizard ]; $form['inputs'][] = [ - 'extra' => '

    Please, configure task '.io_safe_output($this->task['name']).'

    ', + 'label' => __('Auto discover known hardware').ui_print_help_tip( + __( + 'Targets will be monitorized based on its Private Enterprise Number. Requires SNMP.' + ), + true + ), + 'arguments' => [ + 'name' => 'auto_monitor', + 'type' => 'switch', + 'return' => true, + 'value' => (isset($this->task['auto_monitor'])) ? $this->task['auto_monitor'] : 1, + ], ]; $form['inputs'][] = [ - 'label' => __('Module template'), + 'label' => __('Module templates').ui_print_help_tip( + __( + 'Module Host Alive will be added to discovered agents by default.' + ), + true + ), 'arguments' => [ - 'name' => 'id_network_profile', + 'name' => 'id_network_profile[]', 'type' => 'select_from_sql', - 'sql' => 'SELECT id_np, name - FROM tnetwork_profile - ORDER BY name', + 'sql' => 'SELECT tn.id_np, tn.name + FROM tnetwork_profile tn + LEFT JOIN `tnetwork_profile_pen` tp + ON tp.id_np = tn.id_np + WHERE tp.id_np IS NULL + ORDER BY tn.name', 'return' => true, - 'selected' => $this->task['id_network_profile'], + 'selected' => explode( + ',', + $this->task['id_network_profile'] + ), 'nothing_value' => 0, 'nothing' => __('None'), + 'multiple' => true, + 'class' => 'select_multiple', + ], + ]; + + // License precheck. + $license = enterprise_hook('license_get_info'); + $n_agents = 0; + foreach (explode(',', $this->task['subnet']) as $net) { + $mask = explode('/', $net, 2)[1]; + if (empty($mask)) { + $n_agents++; + } else { + $n_agents += pow(2, (32 - $mask)); + } + } + + $limited = false; + if (is_array($license) === true + && $n_agents > ($license['limit'] - $license['count']) + ) { + $limit = ($license['limit'] - $license['count']); + $limited = true; + } + + if ($limited === true) { + ui_print_warning_message( + __( + 'Configured networks could generate %d agents, your license only allows %d, \'review results\' is mandatory.', + $n_agents, + $limit + ) + ); + } + + $form['inputs'][] = [ + 'label' => __('Review results').ui_print_help_tip( + __( + 'Targets must be validated by user before create agents.' + ), + true + ), + 'arguments' => [ + 'name' => 'review_results', + 'type' => 'switch', + 'return' => true, + 'value' => ($this->task['review_mode'] == DISCOVERY_STANDARD) ? (($limited) ? 1 : 0) : 1, + 'disabled' => $limited, + ], + ]; + + // Review limited. + $form['inputs'][] = [ + 'arguments' => [ + 'name' => 'review_limited', + 'type' => 'hidden', + 'return' => true, + 'value' => (($limited === true) ? 1 : 0), ], ]; @@ -930,7 +1169,7 @@ class HostDevices extends Wizard // Submit button. $form['inputs'][] = [ 'arguments' => [ - 'name' => 'submit', + 'name' => 'submit-finish', 'label' => __('Finish'), 'type' => 'submit', 'attributes' => 'class="sub next"', diff --git a/pandora_console/godmode/wizards/Wizard.main.php b/pandora_console/godmode/wizards/Wizard.main.php index 2fe34770ad..7320934826 100644 --- a/pandora_console/godmode/wizards/Wizard.main.php +++ b/pandora_console/godmode/wizards/Wizard.main.php @@ -41,7 +41,7 @@ class Wizard /** * Breadcrum * - * @var array. + * @var array */ public $breadcrum; @@ -233,6 +233,27 @@ class Wizard } + /** + * Return formatted html for error handler. + * + * @param string $message Error mesage. + * + * @return string + */ + public function error($message) + { + if (is_ajax()) { + echo json_encode( + [ + 'error' => ui_print_error_message($message, '', true), + ] + ); + } else { + return ui_print_error_message($message, '', true); + } + } + + /** * To be overwritten. * @@ -566,66 +587,40 @@ class Wizard if (is_array($input['block_content']) === true) { // Print independent block of inputs. - $output .= '
  • '; + $output .= '
    '; $output .= '
      '; foreach ($input['block_content'] as $input) { $output .= $this->printBlockAsGrid($input, $return); } - $output .= '
  • '; + $output .= ''; } else { if ($input['arguments']['type'] != 'hidden' && $input['arguments']['type'] != 'hidden_extended' ) { - if ($input['arguments']['inline'] != 'true') { - $output .= '
    '; - } else { - $output .= '
    '; - if (!isset($input['extra'])) { - $output .= '
    '; - } - - if (isset($input['extra'])) { - $output .= '
    '; - } + $id = ''; + if ($input['id']) { + $id = $input['id']; } - if ($input['arguments']['inline'] == 'true' && isset($input['extra'])) { - $output .= '
    '; + if ($input['arguments']['inline'] != 'true') { + $output .= '
    '; + } else { + $output .= '
    '; } $output .= '
    '; $output .= $input['label']; $output .= '
    '; - if ($input['arguments']['inline'] == 'true' && isset($input['extra'])) { - $output .= '
    '; - } - - if ($input['arguments']['inline'] == 'true' && !isset($input['extra'])) { - $output .= '
    '; - } - if ($input['arguments']['type'] == 'text' || $input['arguments']['type'] == 'text_extended') { $output .= '
    '; $output .= $this->printInput($input['arguments']); $output .= '
    '; } else if ($input['arguments']['inline'] == 'true') { - if (isset($input['extra'])) { - $output .= '
    '; - $output .= '
    '; - } else { - $output .= '
    '; - $output .= '
    '; - } - + $output .= '
    '; $output .= $this->printInput($input['arguments']); $output .= '
    '; - $output .= '
    '; - - if (isset($input['extra'])) { - $output .= '
    '; - } } else { $output .= $this->printInput($input['arguments']); } @@ -800,7 +795,7 @@ class Wizard $cb_function = $data['cb_function']; $cb_args = $data['cb_args']; - $output_head = '
    '; if ($return === false) { diff --git a/pandora_console/include/ajax/task_list.ajax.php b/pandora_console/include/ajax/task_list.ajax.php index 6d50b3c892..1c05ffee79 100644 --- a/pandora_console/include/ajax/task_list.ajax.php +++ b/pandora_console/include/ajax/task_list.ajax.php @@ -24,154 +24,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * ============================================================================ + * + * + * MOVED TO DiscoveryTaskList.class. */ - -require_once $config['homedir'].'/include/graphs/functions_d3.php'; - -$progress_task_discovery = (bool) get_parameter('progress_task_discovery', 0); -$showmap = (bool) get_parameter('showmap', 0); - -if ($progress_task_discovery) { - $id_task = get_parameter('id', 0); - - if ($id_task <= 0) { - echo json_encode(['error' => true]); - return; - } - - $task = db_get_row('trecon_task', 'id_rt', $id_task); - $global_progress = $task['status']; - $summary = json_decode($task['summary'], true); - - $result = '
    '; - if ($task['utimestamp']) { - $result .= '
    '; - $result .= '
    '; - $result .= ''._('Overall Progress').''; - - $result .= '
    '; - $result .= progress_circular_bar( - $id_task, - ($global_progress < 0) ? 100 : $global_progress, - 200, - 200, - '#7eb641', - '%', - '', - '#3A3A3A', - 0 - ); - - $result .= '
    '; - - if ($global_progress > 0) { - switch ($summary['step']) { - case STEP_SCANNING: - $str = __('Scanning network'); - break; - - case STEP_AFT: - $str = __('Finding AFT connectivity'); - break; - - case STEP_TRACEROUTE: - $str = __('Finding traceroute connectivity'); - break; - - case STEP_GATEWAY: - $str = __('Finding gateway connectivity'); - break; - - default: - $str = __('Searching for devices...'); - break; - } - - $result .= '
    '; - $result .= '
    '; - $result .= ''.$str.' '; - $result .= $summary['c_network_name']; - $result .= ''; - - $result .= '
    '; - $result .= progress_circular_bar( - $id_task.'_detail', - $summary['c_network_percent'], - 200, - 200, - '#7eb641', - '%', - '', - '#3A3A3A', - 0 - ); - $result .= '
    '; - } - - $result .= '
    '; - - $i = 0; - $table = new StdClasS(); - $table->class = 'databox data'; - $table->width = '75%'; - $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; - $table->rowid = []; - $table->data = []; - - // Content. - $table->data[$i][0] = ''.__('Hosts discovered').''; - $table->data[$i][1] = ''; - $table->data[$i][1] .= $summary['summary']['discovered']; - $table->data[$i++][1] .= ''; - - $table->data[$i][0] = ''.__('Alive').''; - $table->data[$i][1] = ''; - $table->data[$i][1] .= $summary['summary']['alive']; - $table->data[$i++][1] .= ''; - - $table->data[$i][0] = ''.__('Not alive').''; - $table->data[$i][1] = ''; - $table->data[$i][1] .= $summary['summary']['not_alive']; - $table->data[$i++][1] .= ''; - - $table->data[$i][0] = ''.__('Responding SNMP').''; - $table->data[$i][1] = ''; - $table->data[$i][1] .= $summary['summary']['SNMP']; - $table->data[$i++][1] .= ''; - - $table->data[$i][0] = ''.__('Responding WMI').''; - $table->data[$i][1] = ''; - $table->data[$i][1] .= $summary['summary']['WMI']; - $table->data[$i++][1] .= ''; - - $result .= '
    '.__('Summary').'
    '; - $result .= html_print_table($table, true).'
    '; - } else { - $global_progress = -1; - $result .= ui_print_error_message( - __('No data to show'), - '', - true - ).'
    '; - } - - $result_array['status'] = $global_progress; - $result_array['html'] = $result; - - echo json_encode($result_array); - return; -} - -if ($showmap) { - include_once $config['homedir'].'/include/class/NetworkMap.class.php'; - $id_task = get_parameter('id', 0); - - $map = new NetworkMap( - [ - 'id_task' => $id_task, - 'pure' => 1, - 'widget' => true, - ] - ); - $map->printMap(); -} diff --git a/pandora_console/include/class/AgentWizard.class.php b/pandora_console/include/class/AgentWizard.class.php new file mode 100644 index 0000000000..f638092930 --- /dev/null +++ b/pandora_console/include/class/AgentWizard.class.php @@ -0,0 +1,782 @@ + 'noaccess']); + } + + include 'general/noaccess.php'; + exit; + } + + // Set baseUrl for use it in several locations in this class. + $this->baseUrl = ui_get_full_url('index.php?sec=gagente&sec2=godmode/agentes/configurar_agente&tab=agent_wizard'); + // Capture all parameters before start. + $this->ajaxController = $ajax_controller; + $this->wizardSection = get_parameter('wizard_section', ''); + $this->idAgent = get_parameter('id_agente', ''); + return $this; + } + + + /** + * Run main page. + * + * @return void + */ + public function run() + { + // CSS. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + + // Javascript. + // ui_require_javascript_file('jquery.caret.min'); + $this->loadMainForm(); + $this->performWizard(); + // Load integrated JS + $this->loadJS(); + } + + + /** + * Common Main Wizard form + * + * @return void + */ + private function loadMainForm() + { + // Define name of explorer button + switch ($this->wizardSection) { + case 'snmp_explorer': + case 'snmp_interfaces_explorer': + // Define labels. + $this->actionType = 'snmp'; + $this->actionLabel = __('SNMP Walk'); + // Fill with servers to perform SNMP walk. + $fieldsServers = []; + $fieldsServers[0] = __('Local console'); + if (enterprise_installed()) { + enterprise_include_once('include/functions_satellite.php'); + // Get the servers. + $rows = get_proxy_servers(); + // Check if satellite server has remote configuration enabled. + $satellite_remote = config_agents_has_remote_configuration($this->idAgent); + // Generate a list with allowed servers. + foreach ($rows as $row) { + if ($row['server_type'] == 13) { + $id_satellite = $row['id_server']; + $serverType = ' (Satellite)'; + } else { + $serverType = ' (Standard)'; + } + + $fieldsServers[$row['id_server']] = $row['name'].$serverType; + } + } + + // Fill with SNMP versions allowed. + $fieldsVersions = [ + '1' => '1', + '2' => '2', + '2c' => '2c', + '3' => '3', + ]; + break; + + case 'wmi_explorer': + $this->actionType = 'wmi'; + $this->actionLabel = __('WMI Explorer'); + break; + + default: + $this->actionType = 'none'; + $this->actionLabel = __('Nothing'); + exit; + break; + } + + // Main form. + $form = [ + 'action' => '', + // 'action' => $this->baseUrl, + 'id' => 'main_wizard_form', + 'method' => 'POST', + ]; + + // Inputs. + $inputs = []; + + $inputs[] = [ + 'id' => 'hdn-type-action', + 'arguments' => [ + 'name' => 'type-action', + 'type' => 'hidden', + 'value' => $this->actionType, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Target IP'), + 'id' => 'txt-target-ip', + 'arguments' => [ + 'name' => 'target-ip', + 'input_class' => 'flex-row', + 'type' => 'text', + 'class' => '', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Port'), + 'id' => 'txt-target-port', + 'arguments' => [ + 'name' => 'target-port', + 'input_class' => 'flex-row', + 'type' => 'text', + 'size' => '20', + 'class' => '', + 'return' => true, + ], + ]; + + if ($this->actionType === 'snmp') { + $inputs[] = [ + 'label' => __('Use agent IP'), + 'id' => 'txt-use-agent-ip', + 'arguments' => [ + 'name' => 'use-agent-ip', + 'input_class' => 'flex-row', + 'type' => 'checkbox', + 'class' => '', + 'return' => true, + ], + ]; + } + + if ($this->actionType === 'wmi') { + $inputs[] = [ + 'label' => __('Namespace'), + 'id' => 'txt-namespace', + 'arguments' => [ + 'name' => 'namespace', + 'input_class' => 'flex-row', + 'type' => 'text', + 'class' => '', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Username'), + 'id' => 'txt-username', + 'arguments' => [ + 'name' => 'username', + 'input_class' => 'flex-row', + 'type' => 'text', + 'class' => '', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Password'), + 'id' => 'txt-password', + 'arguments' => [ + 'name' => 'password', + 'input_class' => 'flex-row', + 'type' => 'text', + 'class' => '', + 'return' => true, + ], + ]; + } + + $inputs[] = [ + 'label' => __('Server to execute command'), + 'id' => 'txt-target-port', + 'arguments' => [ + 'name' => 'target-port', + 'input_class' => 'flex-row', + 'type' => 'select', + 'fields' => $fieldsServers, + 'class' => '', + 'return' => true, + ], + ]; + + if ($this->actionType === 'snmp') { + $inputs[] = [ + 'label' => __('SNMP community'), + 'id' => 'txt-snmp-community', + 'arguments' => [ + 'name' => 'snmp-community', + 'input_class' => 'flex-row', + 'type' => 'text', + 'size' => '20', + 'class' => '', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('SNMP version'), + 'id' => 'txt-snmnp-version', + 'arguments' => [ + 'name' => 'snmnp-version', + 'input_class' => 'flex-row', + 'type' => 'select', + 'fields' => $fieldsVersions, + 'class' => '', + 'return' => true, + ], + ]; + } + + $inputs[] = [ + 'arguments' => [ + 'label' => $this->actionLabel, + 'name' => 'action', + 'type' => 'submit', + 'attributes' => 'class="sub next" onclick="performAction();return false;"', + 'return' => true, + ], + ]; + // Prints main form. + html_print_div( + [ + 'class' => 'white_box', + 'content' => $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ), + ] + ); + } + + + /** + * Undocumented function + * + * @return void + */ + public function performWizard() + { + // echo json_encode(['error' => obhd($_REQUEST)]); + // exit; + $sql = sprintf( + 'SELECT npc.id_nc AS component_id, nc.name, nc.type, nc.description, nc.id_group AS `group`, ncg.name AS `group_name` + FROM tnetwork_profile_component AS npc, tnetwork_component AS nc + INNER JOIN tnetwork_component_group AS ncg ON ncg.id_sg = nc.id_group + WHERE npc.id_nc = nc.id_nc AND npc.id_np = %d', + 10 + ); + $moduleBlocks = db_get_all_rows_sql($sql); + + $blockTables = []; + // Build the information of the blocks. + foreach ($moduleBlocks as $block) { + if (key_exists($block['group'], $blockTables) === false) { + $blockTables[$block['group']] = [ + 'name' => $block['group_name'], + 'data' => [], + ]; + } + + $blockTables[$block['group']]['data'][] = [ + 'component_id' => $block['component_id'], + 'name' => $block['name'], + 'type' => $block['type'], + 'description' => $block['description'], + ]; + } + + // Lets generate the block tables. + $output = ''; + foreach ($blockTables as $id_group => $blockTable) { + // Data with all components. + $blockData = $blockTable['data']; + // Creation of list of all components. + $blockComponentList = ''; + foreach ($blockData as $component) { + $blockComponentList .= $component['component_id'].','; + } + + $blockComponentList = chop($blockComponentList, ','); + // Title of Block. + $blockTitle = $blockTable['name']; + $blockTitle .= html_print_div( + [ + 'class' => 'white_table_header_checkbox', + 'content' => html_print_checkbox_switch_extended( + 'sel_block_'.$id_group, + 1, + 0, + false, + 'switchBlockControl(event)', + '', + true + ), + ], + true + ); + + $table = new StdClasS(); + $table->class = 'databox data'; + $table->width = '75%'; + $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; + $table->rowid = []; + $table->data = []; + + $table->cellpadding = 0; + $table->cellspacing = 0; + $table->width = '100%'; + $table->class = 'info_table'; + + $table->head = []; + $table->head[0] = html_print_div(['style' => 'font-weight:700;', 'content' => __('Module Name')], true); + $table->head[1] = html_print_div(['style' => 'font-weight:700;text-align:center;', 'content' => __('Type')], true); + $table->head[2] = html_print_div(['style' => 'font-weight:700;', 'content' => __('Module info')], true); + $table->head[3] = html_print_div(['style' => 'font-weight:700;text-align:center;', 'content' => __('Warning')], true); + $table->head[4] = html_print_div(['style' => 'font-weight:700;text-align:center;', 'content' => __('Critical')], true); + $table->head[5] = html_print_div(['style' => 'font-weight:700;margin-right:1.2em;', 'content' => __('Active')], true); + + $table->size = []; + $table->size[0] = '15%'; + $table->size[1] = '3%'; + $table->size[3] = '210px'; + $table->size[4] = '210px'; + $table->size[5] = '3%'; + + $table->align = []; + $table->align[5] = 'right'; + + $table->data = []; + + foreach ($blockData as $module) { + // Module Name column. + $data[0] = $module['name']; + // Module Type column. + $data[1] = ui_print_moduletype_icon($module['type'], true); + // Module info column. + $data[2] = mb_strimwidth(io_safe_output($module['description']), 0, 150, '...'); + // Warning column. + $data[3] = html_print_div( + [ + 'class' => 'wizard-column-levels', + 'content' => 'Min: '.html_print_input_text( + 'warning_min_'.$module['component_id'], + '0', + '', + 3, + 4, + true + ).' ', + ], + true + ); + $data[3] .= html_print_div( + [ + 'class' => 'wizard-column-levels', + 'content' => 'Max: '.html_print_input_text( + 'warning_max_'.$module['component_id'], + '0', + '', + 3, + 4, + true + ), + ], + true + ); + $data[3] .= html_print_div( + [ + 'class' => 'wizard-column-levels', + 'style' => 'margin-top: 0.3em;', + 'content' => 'Inv: '.html_print_checkbox( + 'warning_inv_'.$module['component_id'], + 0, + false, + true, + false + ), + ], + true + ); + // Critical column. + $data[4] = html_print_div( + [ + 'class' => 'wizard-column-levels', + 'content' => 'Min: '.html_print_input_text( + 'critical_min_'.$module['component_id'], + '0', + '', + 3, + 4, + true + ).' ', + ], + true + ); + $data[4] .= html_print_div( + [ + 'class' => 'wizard-column-levels', + 'content' => 'Max: '.html_print_input_text( + 'critical_max_'.$module['component_id'], + '0', + '', + 3, + 4, + true + ), + ], + true + ); + $data[4] .= html_print_div( + [ + 'class' => 'wizard-column-levels', + 'style' => 'margin-top: 0.3em;', + 'content' => 'Inv: '.html_print_checkbox( + 'critical_inv_'.$module['component_id'], + 0, + false, + true, + false + ), + ], + true + ); + // Activation column. + $data[5] = html_print_checkbox_switch_extended('sel_module_'.$id_group.'_'.$module['component_id'], 1, 0, false, 'switchBlockControl(event)', '', true); + + array_push($table->data, $data); + } + + $content = html_print_table($table, true); + + $output .= ui_toggle($content, $blockTitle, '', '', false, true); + } + + html_print_div( + [ + 'class' => 'white_box', + 'style' => 'margin-top: 20px;', + 'content' => $output, + ] + ); + + // Form. Not used at this moment. + $form = [ + 'action' => $this->baseUrl, + 'id' => 'modal_form_action_response', + 'method' => 'POST', + 'class' => 'modal', + 'extra' => '', + ]; + + // Inputs. + $inputs = []; + + $inputs[] = [ + 'id' => 'inp-id_np', + 'arguments' => [ + 'name' => 'id_np', + 'type' => 'hidden', + 'value' => '69', + 'return' => true, + ], + ]; + + $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + true + ] + ); + } + + + /** + * Perform SNMP + * + * @return void + */ + private function performSNMP() + { + echo 'HOLA'; + } + + + /** + * Perform WMI + * + * @return void + */ + private function performWMI() + { + + } + + + /** + * Generate the JS needed for use inside + * + * @return void + */ + private function loadJS() + { + $str = ''; + + ob_start(); + ?> + + ajaxController = $ajax_page; + $this->offset = ''; + $this->baseUrl = ui_get_full_url( + 'index.php?sec=configuration_wizard_setup&sec2=godmode/modules/private_enterprise_numbers' + ); + + } + + + /** + * Returns an array with all the credentials matching filter and ACL. + * + * @param array $fields Fields array or 'count' keyword to retrieve count. + * @param array $filter Filters to be applied. + * @param integer $offset Offset (pagination). + * @param integer $limit Limit (pagination). + * @param string $order Sort order. + * @param string $sort_field Sort field. + * + * @return array With all results or false if error. + * @throws Exception On error. + */ + public static function getAll( + $fields, + $filter=null, + $offset=null, + $limit=null, + $order=null, + $sort_field=null + ) { + $sql_filters = []; + $order_by = ''; + $pagination = ''; + + $count = false; + if (!is_array($fields) && $fields == 'count') { + $fields = ['*']; + $count = true; + } else if (!is_array($fields)) { + error_log('[configPEN.getAll] Fields must be an array or "count".'); + throw new Exception('[configPEN.getAll] Fields must be an array or "count".'); + } + + if (is_array($filter)) { + if (!empty($filter['free_search'])) { + $sql_filters[] = vsprintf( + ' AND (lower(`manufacturer`) like lower("%%%s%%") + OR pen = "%s") ', + array_fill(0, 2, $filter['free_search']) + ); + } + + if (!empty($filter['pen'])) { + $sql_filters[] = sprintf( + ' AND `pen` = %d', + $filter['pen'] + ); + } + } + + if (isset($order)) { + $dir = 'asc'; + if ($order == 'desc') { + $dir = 'desc'; + }; + + if (in_array( + $sort_field, + [ + 'pen', + 'manufacturer', + 'description', + ] + ) + ) { + $order_by = sprintf( + 'ORDER BY `%s` %s', + $sort_field, + $dir + ); + } + } + + if (isset($limit) && $limit > 0 + && isset($offset) && $offset >= 0 + ) { + $pagination = sprintf( + ' LIMIT %d OFFSET %d ', + $limit, + $offset + ); + } + + $sql = sprintf( + 'SELECT %s + FROM `tpen` + WHERE 1=1 + %s + %s + %s', + join(',', $fields), + join(' ', $sql_filters), + $order_by, + $pagination + ); + + if ($count) { + $sql = sprintf('SELECT count(*) as n FROM ( %s ) tt', $sql); + + return db_get_value_sql($sql); + } + + return db_get_all_rows_sql($sql); + } + + + /** + * AJAX: Return JSON content for datatable. + * + * @return void + */ + function draw() + { + global $config; + + // Datatables offset, limit and order. + $filter = get_parameter('filter', []); + $start = get_parameter('start', 0); + $length = get_parameter('length', $config['block_size']); + $order = get_datatable_order(true); + try { + ob_start(); + + $fields = ['*']; + + // Retrieve data. + $data = $this->getAll( + // Fields. + $fields, + // Filter. + $filter, + // Offset. + $start, + // Limit. + $length, + // Order. + $order['direction'], + // Sort field. + $order['field'] + ); + + // Retrieve counter. + $count = $this->getAll( + 'count', + $filter + ); + + if ($data) { + $data = array_reduce( + $data, + function ($carry, $item) { + // Transforms array of arrays $data into an array + // of objects, making a post-process of certain fields. + $tmp = (object) $item; + + $tmp->description = io_safe_output($tmp->description); + $tmp->manufacturer = io_safe_output($tmp->manufacturer); + + $tmp->options = ''; + + $tmp->options = ''; + $tmp->options .= html_print_image( + 'images/eye.png', + true, + ['title' => __('Show')] + ); + $tmp->options .= ''; + $tmp->options .= ''; + $tmp->options .= html_print_image( + 'images/cross.png', + true, + ['title' => __('Delete')] + ); + $tmp->options .= ''; + + $carry[] = $tmp; + return $carry; + } + ); + } + + // Datatables format: RecordsTotal && recordsfiltered. + echo json_encode( + [ + 'data' => $data, + 'recordsTotal' => $count, + 'recordsFiltered' => $count, + ] + ); + // Capture output. + $response = ob_get_clean(); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + exit; + } + + // If not valid, show error with issue. + json_decode($response); + if (json_last_error() == JSON_ERROR_NONE) { + // If valid dump. + echo $response; + } else { + echo json_encode( + ['error' => $response] + ); + } + + exit; + + } + + + /** + * Run main page. + * + * @return void + */ + public function run() + { + // Require specific CSS and JS. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + ui_require_css_file('pen'); + + // Header section. + // Breadcrums. + $this->setBreadcrum([]); + + $this->prepareBreadcrum( + [ + [ + 'link' => '', + 'label' => __('Configuration'), + 'selected' => false, + ], + [ + 'link' => '', + 'label' => __('Templates'), + 'selected' => false, + ], + [ + 'link' => $this->baseUrl, + 'label' => __('Private Enterprise Numbers'), + 'selected' => true, + ], + ], + true + ); + + ui_print_page_header( + __('Private Enterprise Numbers'), + '', + false, + '', + true, + '', + false, + '', + GENERIC_SIZE_TEXT, + '', + $this->printHeader(true) + ); + + // Definition for AJAX. + html_print_input_hidden( + 'ajax_file', + ui_get_full_url('ajax.php', false, false, false) + ); + + // Ajax page (hidden). + html_print_input_hidden( + 'ajax_page', + $this->ajaxController + ); + + // Allow message area. + html_print_div(['id' => 'message_show_area']); + // Prints the main table. + html_print_div( + [ + 'id' => 'main_table_area', + 'content' => $this->createMainTable(), + ] + ); + } + + + /** + * Load modal information for PEN management. + * + * Ajax. Direct HTML. + * + * @return void + */ + public function loadModal() + { + $values = []; + $id = (int) get_parameter('pen', 0); + if ($id > 0) { + $values = $this->getAll( + // Fields. + ['*'], + // Filter. + ['pen' => $id] + ); + if (is_array($values)) { + $values = $values[0]; + } + } + + $form = [ + 'action' => '#', + 'id' => 'modal_form', + 'onsubmit' => 'return false;', + 'class' => '', + ]; + + $inputs = []; + + $arguments = [ + 'name' => 'pen', + 'type' => 'number', + 'value' => $values['pen'], + 'required' => true, + 'return' => true, + 'size' => 50, + ]; + + if ((bool) $values['pen']) { + $arguments['disabled'] = true; + } + + $inputs[] = [ + 'label' => __('PEN'), + 'class' => 'flex-row', + 'id' => 'div-pen', + 'arguments' => $arguments, + ]; + + $inputs[] = [ + 'label' => __('Manufacturer'), + 'class' => 'flex-row', + 'arguments' => [ + 'name' => 'manufacturer', + 'id' => 'manufacturer', + 'type' => 'text', + 'required' => true, + 'value' => io_safe_output($values['manufacturer']), + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Description'), + 'class' => 'flex-row', + 'arguments' => [ + 'name' => 'description', + 'id' => 'description', + 'type' => 'textarea', + 'value' => io_safe_output($values['description']), + 'return' => true, + 'rows' => 50, + 'columns' => 30, + ], + ]; + + echo '
    '; + echo parent::printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + echo '
    '; + } + + + /** + * Delete a manufacturer register from db. + * + * @return void + */ + public function delete() + { + $pen = get_parameter('pen', 0); + + if (empty($pen)) { + echo json_encode(['error' => __('PEN is required')]); + } else { + if (db_process_sql_delete('tpen', ['pen' => $pen]) !== false) { + echo json_encode(['result' => __('Successfully deleted')]); + } else { + global $config; + echo json_encode(['error' => $config['dbconnection']->error]); + } + } + + } + + + /** + * Add or update a manufacturer to private enterprise numbers. + * + * @return void + */ + public function add() + { + $pen = get_parameter('pen', 0); + $manufacturer = get_parameter('manufacturer', ''); + $description = get_parameter('description', ''); + $is_new = (bool) get_parameter('is_new', false); + + if (empty($pen)) { + $error = __('PEN is required.'); + } + + if (empty($manufacturer)) { + $error = __('Manufacturer is required'); + } + + if (!empty($error)) { + echo json_encode( + ['error' => $error] + ); + } + + // Add if not exists. + $current = $this->getAll(['pen'], ['pen' => $pen]); + + if ($current === false) { + // New. + if ($is_new === false) { + echo json_encode( + [ + 'error' => __('This PEN definition does not exist'), + ] + ); + exit; + } + + $rs = db_process_sql_insert( + 'tpen', + [ + 'pen' => $pen, + 'manufacturer' => $manufacturer, + 'description' => $description, + ] + ); + $str = __('created'); + } else { + // Update. + if ($is_new === true) { + echo json_encode( + [ + 'error' => __('This PEN definition already exists'), + ] + ); + exit; + } + + $rs = db_process_sql_update( + 'tpen', + [ + 'manufacturer' => $manufacturer, + 'description' => $description, + ], + ['pen' => $pen] + ); + $str = __('updated'); + } + + if ($rs === false) { + global $config; + echo json_encode(['error' => $config['dbconnection']->error]); + } else { + echo json_encode(['result' => __('Succesfully %s', $str)]); + } + } + + + /** + * Create the main table with the PENs info + * + * @return string Return entire the table + */ + public function createMainTable() + { + global $config; + + $output = ''; + + // Datatables list. + try { + $columns = [ + 'pen', + 'manufacturer', + 'description', + 'options', + ]; + + $column_names = [ + __('PEN'), + __('Manufacturer'), + __('Description'), + [ + 'text' => __('Options'), + 'class' => 'action_buttons', + ], + ]; + + $this->tableId = 'keystore'; + // Load datatables user interface. + $output .= ui_print_datatable( + [ + 'id' => $this->tableId, + 'return' => true, + 'class' => 'info_table', + 'style' => 'width: 100%', + 'columns' => $columns, + 'column_names' => $column_names, + 'ajax_url' => $this->ajaxController, + 'ajax_data' => ['method' => 'draw'], + 'no_sortable_columns' => [-1], + 'order' => [ + 'field' => 'pen', + 'direction' => 'asc', + ], + 'search_button_class' => 'sub filter float-right', + 'form' => [ + 'inputs' => [ + [ + 'label' => __('Free search'), + 'type' => 'text', + 'class' => 'mw250px', + 'id' => 'free_search', + 'name' => 'free_search', + ], + ], + ], + ] + ); + } catch (Exception $e) { + echo $e->getMessage(); + } + + // Auxiliar div. + $output .= ''; + $output .= ''; + $output .= ''; + + // Create button. + $output .= parent::printInput( + [ + 'type' => 'submit', + 'name' => 'create', + 'label' => __('Register manufacturer'), + 'attributes' => 'class="sub next"', + 'return' => true, + ] + ); + + ob_start(); + ?> + + ui_print_error_message($message, '', true), + ] + ); + } else { + return ui_print_error_message($message, '', true); + } + } + + /** * Print input using functions html lib. * @@ -725,6 +746,7 @@ class HTML ) { $form = $data['form']; $inputs = $data['inputs']; + $rawInputs = $data['rawInputs']; $js = $data['js']; $rawjs = $data['js_block']; $cb_function = $data['cb_function']; @@ -767,6 +789,11 @@ class HTML $output .= ''; + // There is possible add raw inputs for this form. + if (empty($rawInputs) === false) { + $output .= $rawInputs; + } + if ($print_white_box === true) { $output .= '
    '; } @@ -800,7 +827,7 @@ class HTML $form = $data['form']; $rows = $data['rows']; - + $rawInputs = $data['rawInputs']; $js = $data['js']; $rawjs = $data['js_block']; $cb_function = $data['cb_function']; @@ -875,6 +902,11 @@ class HTML } } + // There is possible add raw inputs for this form. + if (empty($rawInputs) === false) { + $output .= $rawInputs; + } + $output .= '
    '; $output .= '
      '.$output_submit.'
    '; @@ -905,6 +937,7 @@ class HTML { $form = $data['form']; $inputs = $data['inputs']; + $rawInputs = $data['rawInputs']; $js = $data['js']; $rawjs = $data['js_block']; $cb_function = $data['cb_function']; @@ -940,7 +973,13 @@ class HTML } $output .= ''; + // There is possible add raw inputs for this form. + if (empty($rawInputs) === false) { + $output .= $rawInputs; + } + $output .= '
    '; + $output .= '
      '.$output_submit.'
    '; $output .= ''; $output .= ''; @@ -1000,4 +1039,72 @@ class HTML } + /** + * Returns a n-dimensional array (data) into a html tree structure. + * + * Advanced documentation: + * https://www.jqueryscript.net/other/Checkable-Hierarchical-Tree.html + * + * @param string $target Target DOM id. + * @param array $data N-dimensional array. + * @param string $onclick Onclick function. + * @param string $onchange Onchange function. + * + * @return string + */ + public static function printTree( + $target, + $data, + $onclick='', + $onchange='' + ) { + ui_require_css_file('simTree'); + ui_require_javascript_file('simTree'); + + /* + * SAMPLE SELECT ALL. + * + * echo '
    '; + * echo ''; + * echo __('Please select devices to be monitored'); + * echo '
    '; + * echo ''; + * echo ''; + * echo '
    '; + * echo '
    '; + * + * END SAMPLE SELECT ALL. + */ + + $output = ' +'; + + return $output; + } + + } diff --git a/pandora_console/include/class/ModuleTemplates.class.php b/pandora_console/include/class/ModuleTemplates.class.php new file mode 100644 index 0000000000..585a40aa13 --- /dev/null +++ b/pandora_console/include/class/ModuleTemplates.class.php @@ -0,0 +1,1429 @@ + 'noaccess']); + } + + include 'general/noaccess.php'; + exit; + } + + // Set baseUrl for use it in several locations in this class. + $this->baseUrl = ui_get_full_url('index.php?sec=gmodules&sec2=godmode/modules/manage_module_templates'); + // Capture all parameters before start. + $this->id_np = get_parameter('id_np', -1); + $this->action = get_parameter('action_button', ''); + // Profile exists. Set the attributes with the info. + if ($this->id_np > 0 || empty($this->action)) { + $this->setNetworkProfile(); + } + + $this->offset = (int) get_parameter('offset', 0); + $this->ajaxController = $ajax_controller; + // Get all of PENs valid for autocomplete. + $getPENs = db_get_all_rows_sql('SELECT pen,manufacturer FROM tpen'); + $outputPENs = []; + + $this->validPen = ''; + $this->penRefs = []; + foreach ($getPENs as $pen) { + $this->validPen .= ((int) $pen['pen']).','; + $this->penRefs[] = [ + 'label' => io_safe_output($pen['manufacturer']), + 'value' => $pen['pen'], + ]; + // Reverse autocompletion. + $this->penRefs[] = [ + 'label' => $pen['pen'], + 'value' => $pen['pen'], + ]; + } + + chop($this->validPen); + + return $this; + } + + + /** + * Run main page. + * + * @return void + */ + public function run() + { + // CSS. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + + // Javascript. + ui_require_javascript_file('jquery.caret.min'); + + // Breadcrums. + $this->setBreadcrum([]); + + if ($this->id_np > 0) { + // Add a breadcrumb with the current template. + $urlToGo = $this->baseUrl.'&id_np='.$this->id_np; + + $this->prepareBreadcrum( + [ + ['label' => __('Configuration')], + ['label' => __('Templates')], + [ + 'link' => $this->baseUrl, + 'label' => __('Module template management'), + 'selected' => false, + ], + [ + 'link' => $urlToGo, + 'label' => $this->name, + 'selected' => true, + ], + ], + true + ); + } else { + $this->prepareBreadcrum( + [ + ['label' => __('Configuration')], + ['label' => __('Templates')], + [ + 'link' => $this->baseUrl, + 'label' => __('Module template management'), + 'selected' => true, + ], + ], + true + ); + } + + // Prints the header. + ui_print_page_header( + __('Module template management'), + '', + false, + '', + true, + '', + false, + '', + GENERIC_SIZE_TEXT, + '', + $this->printHeader(true) + ); + + // Process the data if action is required. + if (!empty($this->action)) { + $this->processData(); + } + + if ($this->id_np === -1) { + // List all Module Blocks. + $this->moduleTemplateList(); + } else { + // Show form for create or update template. + $this->moduleTemplateForm(); + } + + $this->loadJS(); + } + + + /** + * Minor function to dump json message as ajax response. + * + * @param string $type Type: result || error. + * @param string $msg Message. + * + * @return void + */ + private function ajaxMsg($type, $msg) + { + if ($type == 'error') { + echo json_encode( + [ + $type => ui_print_error_message( + __($msg), + '', + true + ), + ] + ); + } else { + echo json_encode( + [ + $type => ui_print_success_message( + __($msg), + '', + true + ), + ] + ); + } + + exit; + } + + + /** + * Save or Update the data received. + * + * @return void + */ + public function processData() + { + // Only needed if process data. + $modulesToAdd = get_parameter('add-modules-components', ''); + // Evaluate the modules allowed. + if (!empty($this->action)) { + // Success variable. + $success = false; + $this->name = get_parameter('name', ''); + $this->description = get_parameter('description', ''); + $this->pen = get_parameter('pen', ''); + + switch ($this->action) { + case 'Update': + $dbResult_tnp = db_process_sql_update( + 'tnetwork_profile', + [ + 'name' => $this->name, + 'description' => $this->description, + ], + ['id_np' => $this->id_np] + ); + if ($dbResult_tnp === false) { + $success = false; + } else { + db_process_sql_delete('tnetwork_profile_pen', ['id_np' => $this->id_np]); + if (empty($this->pen)) { + $success = true; + } else { + $pensList = explode(',', $this->pen); + // Set again the new PENs associated. + foreach ($pensList as $currentPen) { + $dbResult_pen = db_process_sql_insert( + 'tnetwork_profile_pen', + [ + 'pen' => $currentPen, + 'id_np' => $this->id_np, + ] + ); + if ($dbResult_pen === false) { + $success = false; + break; + } + + $success = true; + } + } + } + + if ($success === true) { + $msg = __('Template %s successfully updated', $this->name); + } else { + $msg = __('Error updating template'); + } + break; + + case 'Create': + $dbResult_tnp = db_process_sql_insert( + 'tnetwork_profile', + [ + 'name' => $this->name, + 'description' => $this->description, + ] + ); + // The insert gone fine! + if ($dbResult_tnp != false) { + // Set the new id_np. + $this->id_np = $dbResult_tnp; + if (empty($this->pen)) { + $success = true; + } else { + $pensList = explode(',', $this->pen); + // Insert all of new PENs associated with this id_np. + foreach ($pensList as $currentPen) { + $dbResult_pen = db_process_sql_insert( + 'tnetwork_profile_pen', + [ + 'pen' => $currentPen, + 'id_np' => $this->id_np, + ] + ); + // If something is wrong, is better stop. + if ($dbResult_pen === false) { + break; + } + + $success = true; + } + } + } + + if ($success === true) { + $msg = __('Template %s successfully created', $this->name); + } else { + $msg = __('Error creating template'); + } + break; + + case 'Delete': + $success = db_process_sql_delete('tnetwork_profile', ['id_np' => $this->id_np]); + + if ($success != false) { + $msg = __('Template %s successfully deleted', $this->name); + } else { + $msg = __('Error deleting %s template', $this->name); + } + + // Reset id_np for show the templates list. + $this->id_np = -1; + break; + + case 'Export': + global $config; + + $id_network_profile = safe_int($this->id_np); + if (empty($id_network_profile)) { + return false; + } + + $filter['id_np'] = $id_network_profile; + + $profile_info = @db_get_row_filter('tnetwork_profile', $filter, false); + + if (empty($profile_info)) { + $success = false; + // ui_print_error_message(__('This template does not exist')); + return; + } + + // It's important to keep the structure and order in the same way for backwards compatibility. + switch ($config['dbtype']) { + case 'mysql': + $sql = sprintf( + ' + SELECT components.name, components.description, components.type, components.max, components.min, components.module_interval, + components.tcp_port, components.tcp_send, components.tcp_rcv, components.snmp_community, components.snmp_oid, + components.id_module_group, components.id_modulo, components.plugin_user, components.plugin_pass, components.plugin_parameter, + components.max_timeout, components.max_retries, components.history_data, components.min_warning, components.max_warning, components.str_warning, components.min_critical, + components.max_critical, components.str_critical, components.min_ff_event, components.dynamic_interval, components.dynamic_max, components.dynamic_min, components.dynamic_two_tailed, comp_group.name AS group_name, components.critical_instructions, components.warning_instructions, components.unknown_instructions + FROM `tnetwork_component` AS components, tnetwork_profile_component AS tpc, tnetwork_component_group AS comp_group + WHERE tpc.id_nc = components.id_nc + AND components.id_group = comp_group.id_sg + AND tpc.id_np = %d', + $this->id_np + ); + break; + + case 'postgresql': + $sql = sprintf( + ' + SELECT components.name, components.description, components.type, components.max, components.min, components.module_interval, + components.tcp_port, components.tcp_send, components.tcp_rcv, components.snmp_community, components.snmp_oid, + components.id_module_group, components.id_modulo, components.plugin_user, components.plugin_pass, components.plugin_parameter, + components.max_timeout, components.max_retries, components.history_data, components.min_warning, components.max_warning, components.str_warning, components.min_critical, + components.max_critical, components.str_critical, components.min_ff_event, comp_group.name AS group_name, components.critical_instructions, components.warning_instructions, components.unknown_instructions + FROM "tnetwork_component" AS components, tnetwork_profile_component AS tpc, tnetwork_component_group AS comp_group + WHERE tpc.id_nc = components.id_nc + AND components.id_group = comp_group.id_sg + AND tpc.id_np = %d', + $this->id_np + ); + break; + + case 'oracle': + $sql = sprintf( + ' + SELECT components.name, components.description, components.type, components.max, components.min, components.module_interval, + components.tcp_port, components.tcp_send, components.tcp_rcv, components.snmp_community, components.snmp_oid, + components.id_module_group, components.id_modulo, components.plugin_user, components.plugin_pass, components.plugin_parameter, + components.max_timeout, components.max_retries, components.history_data, components.min_warning, components.max_warning, components.str_warning, components.min_critical, + components.max_critical, components.str_critical, components.min_ff_event, comp_group.name AS group_name, components.critical_instructions, components.warning_instructions, components.unknown_instructions + FROM tnetwork_component AS components, tnetwork_profile_component AS tpc, tnetwork_component_group AS comp_group + WHERE tpc.id_nc = components.id_nc + AND components.id_group = comp_group.id_sg + AND tpc.id_np = %d', + $this->id_np + ); + break; + } + + $components = db_get_all_rows_sql($sql); + + $row_names = []; + $inv_names = []; + // Find the names of the rows that we are getting and throw away the duplicate numeric keys + foreach ($components[0] as $row_name => $detail) { + if (is_numeric($row_name)) { + $inv_names[] = $row_name; + } else { + $row_names[] = $row_name; + } + } + + $fileName = io_safe_output($profile_info['name']); + // Send headers to tell the browser we're sending a file + header('Content-type: application/octet-stream'); + header('Content-Disposition: attachment; filename='.preg_replace('/\s/', '_', $fileName).'.csv'); + header('Pragma: no-cache'); + header('Expires: 0'); + + // Clean up output buffering + while (@ob_end_clean()) { + } + + // Then print the first line (row names) + echo '"'.implode('","', $row_names).'"'; + echo "\n"; + + // Then print the rest of the data. Encapsulate in quotes in case we have comma's in any of the descriptions + foreach ($components as $row) { + foreach ($inv_names as $bad_key) { + unset($row[$bad_key]); + } + + echo '"'.implode('","', $row).'"'; + echo "\n"; + } + + // We're done here. The original page will still be there + exit; + + break; + + default: + // There is possible want do an action detailed. + $action_detailed = explode('_', $this->action); + // Action deletion. + if ($action_detailed[0] === 'del') { + // Block or Module is affected. + switch ($action_detailed[1]) { + case 'module': + $success = db_process_sql_delete( + 'tnetwork_profile_component', + 'id_nc='.$action_detailed[2].' AND id_np='.$this->id_np + ); + + if ($success != false) { + $msg = __('Module successfully deleted'); + } else { + $msg = __('Error deleting module'); + } + break; + + case 'block': + $success = db_process_sql_delete( + 'tnetwork_profile_component', + 'id_nc in ('.$action_detailed[2].') AND id_np='.$this->id_np + ); + + if ($success != false) { + $msg = __('Block successfully deleted'); + } else { + $msg = __('Error deleting block'); + } + break; + + case 'template': + if ($action_detailed[2] === 'all') { + $success = db_process_sql_delete( + 'tnetwork_profile', + ['1' => 1] + ); + + if ($success != false) { + $msg = __('All templates deleted'); + } else { + $msg = __('Error deleting all templates'); + } + } else { + $success = db_process_sql_delete( + 'tnetwork_profile', + 'id_np in ('.$action_detailed[2].')' + ); + + if ($success != false) { + $msg = __('Selected templates deleted'); + } else { + $msg = __('Error deleting selected templates'); + } + } + + $this->id_np = -1; + break; + + default: + // Do nothing. + break; + } + } else { + $msg = __('Something gone wrong. Please, try again'); + } + break; + } + + if ($success === false) { + ui_print_error_message($msg); + } else { + ui_print_success_message($msg); + } + } else if ($modulesToAdd != '') { + $modulesToAddList = explode(',', $modulesToAdd); + foreach ($modulesToAddList as $module) { + db_process_sql_insert( + 'tnetwork_profile_component', + [ + 'id_nc' => $module, + 'id_np' => $this->id_np, + ] + ); + } + + $this->ajaxMsg('result', __('Components added sucessfully')); + } + } + + + /** + * Show the adding modules form + * + * @return void + */ + public function addingModulesForm() + { + // Get the groups for select input. + $result = db_get_all_rows_in_table('tnetwork_component_group', 'name'); + if ($result === false) { + $result = []; + } + + // 2 arrays. 1 with the groups, 1 with the groups by parent + $groups = []; + $groups_compound = []; + + foreach ($result as $row) { + $groups[$row['id_sg']] = $row['name']; + } + + foreach ($result as $row) { + if ($row['parent'] > 1) { + $groups_compound[$row['id_sg']] = $groups[$row['parent']].' / '.$row['name']; + } else { + $groups_compound[$row['id_sg']] = $row['name']; + } + } + + $result = db_get_all_rows_sql( + 'SELECT id_nc, name, id_group + FROM tnetwork_component + ORDER BY name' + ); + + $entireComponentsList = []; + $components = []; + if ($result === false) { + $result = []; + } + + foreach ($result as $row) { + $strIdGroup = (string) $row['id_group']; + if (!isset($entireComponentsList[$strIdGroup])) { + $entireComponentsList[$strIdGroup] = $row['id_nc']; + } else { + $entireComponentsList[$strIdGroup] .= ','.$row['id_nc']; + } + + $components[$row['id_nc']] = $row['name']; + } + + $entireComponentsList = json_encode($entireComponentsList); + + // Main form. + $form = [ + 'action' => $this->baseUrl, + 'id' => 'add_module_form', + 'method' => 'POST', + 'class' => 'modal', + 'extra' => '', + ]; + + // Inputs. + $inputs = []; + + $inputs[] = [ + 'id' => 'inp-id_np', + 'arguments' => [ + 'name' => 'id_np', + 'type' => 'hidden', + 'value' => $this->id_np, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Filter'), + 'id' => 'txt-add-modules-filter', + 'arguments' => [ + 'input_class' => 'flex-row', + 'name' => 'filter', + 'type' => 'text', + 'size' => '40', + 'class' => 'float-right', + 'onKeyDown' => 'filterTextComponents(event);', + 'value' => '', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Group'), + 'id' => 'add-modules-group', + 'arguments' => [ + 'input_class' => 'flex-row', + 'type' => 'select', + 'script' => 'filterGroupComponents(event);', + 'class' => 'float-right', + 'fields' => $groups_compound, + 'nothing' => 'Group - All', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'id' => 'group-components', + 'arguments' => [ + 'name' => 'group-components', + 'type' => 'hidden', + 'value' => $entireComponentsList, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Components'), + 'id' => 'slc-add-modules-components', + 'arguments' => [ + 'name' => 'add-modules-components', + 'input_class' => 'flex-row', + 'style' => 'width:100%;margin-top: 1em;', + 'type' => 'select', + 'multiple' => true, + 'fields' => $components, + 'return' => true, + ], + ]; + + $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + true + ] + ); + } + + + /** + * General setter + * + * @return void + */ + private function setNetworkProfile() + { + $profileInfo = db_get_row('tnetwork_profile', 'id_np', $this->id_np); + $this->name = $profileInfo['name']; + $this->description = $profileInfo['description']; + + $penInfo = db_get_all_rows_filter('tnetwork_profile_pen', ['id_np' => $this->id_np]); + $penList = []; + foreach ($penInfo as $pen) { + $penList[] = $pen['pen']; + } + + $this->pen = implode(',', $penList); + } + + + /** + * Create the table with the list of Blocks Templates + * + * @return void + */ + public function moduleTemplateList() + { + global $config; + // Get the count of Blocks. + $countModuleTemplates = db_get_value( + 'count(*)', + 'tnetwork_profile' + ); + + // Get all the data. + $resultModuleTemplatesTable = db_get_all_rows_filter( + 'tnetwork_profile', + [ + 'order' => 'name', + 'limit' => $config['block_size'], + 'offset' => $this->offset, + ] + ); + + ui_pagination($countModuleTemplates, $this->baseUrl, $this->offset); + // Create the table with Module Block list. + $table = new StdClasS(); + $table->class = 'databox data'; + $table->width = '75%'; + $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; + $table->rowid = []; + $table->data = []; + + $table->cellpadding = 0; + $table->cellspacing = 0; + $table->width = '100%'; + $table->class = 'info_table'; + + $table->head = []; + $table->head[0] = html_print_checkbox('all_delete', 0, false, true, false); + + $table->head[1] = __('Name'); + $table->head[2] = __('Description'); + $table->head[3] = ''.__('Action').''; + $table->size = []; + $table->size[0] = '20px'; + $table->size[2] = '65%'; + $table->size[3] = '15%'; + + $table->align = []; + $table->align[3] = 'left'; + + $table->data = []; + + foreach ($resultModuleTemplatesTable as $row) { + $data = []; + $data[0] = html_print_checkbox_extended('delete_multiple[]', $row['id_np'], false, false, '', 'class="check_delete"', true); + $data[1] = ''.io_safe_output($row['name']).''; + $data[2] = ui_print_truncate_text(io_safe_output($row['description']), 'description', true, true, true, '[…]'); + $table->cellclass[][3] = 'action_buttons'; + $data[3] = html_print_input_image( + 'delete_profile', + 'images/cross.png', + $row['id_np'], + '', + true, + ['onclick' => 'if (!confirm(\''.__('Are you sure?').'\')) return false;'] + ); + $data[3] .= html_print_input_image( + 'export_profile', + 'images/csv.png', + $row['id_np'], + '', + true, + ['title' => 'Export to CSV'] + ); + $data[3] = ''.html_print_image('images/cross.png', true, ['title' => __('Delete')]).''; + $data[3] .= ''.html_print_image('images/csv.png', true, ['title' => __('Export to CSV')]).''; + + array_push($table->data, $data); + } + + html_print_table($table); + + $output = '
    '; + + $form = [ + 'method' => 'POST', + 'action' => $this->baseUrl, + 'id' => 'main_management_form', + ]; + + $inputs[] = [ + 'arguments' => [ + 'name' => 'id_np', + 'type' => 'hidden', + 'value' => 0, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'arguments' => [ + 'label' => __('Create'), + 'name' => 'crt', + 'type' => 'submit', + 'attributes' => 'class="sub wand"', + 'return' => true, + ], + ]; + + $inputs[] = [ + 'arguments' => [ + 'label' => __('Delete selected'), + 'name' => 'erase', + 'type' => 'button', + 'attributes' => 'class="sub cancel"', + 'return' => true, + ], + ]; + + $output .= $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + + $output .= '
    '; + + echo $output; + } + + + /** + * Prints Form for template management + * + * @return mixed + */ + public function moduleTemplateForm() + { + $createNewTemplate = ($this->id_np == 0) ? true : false; + + if ($createNewTemplate) { + // Assignation for submit button. + $formButtonClass = 'sub wand'; + $formButtonValue = 'create'; + $formButtonLabel = __('Create'); + } else { + // Assignation for submit button. + $formButtonClass = 'sub upd'; + $formButtonValue = 'update'; + $formButtonLabel = __('Update'); + } + + // Main form. + $form = [ + 'action' => $this->baseUrl, + 'id' => 'module_template_form', + 'method' => 'POST', + 'class' => 'databox filters', + 'extra' => 'id="module_template_form"', + ]; + + // Inputs. + $inputs = []; + // Inputs. + $rawInputs = ''; + + $inputs[] = [ + 'id' => 'inp-id_np', + 'arguments' => [ + 'name' => 'id_np', + 'type' => 'hidden', + 'value' => $this->id_np, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'id' => 'inp-valid-pen', + 'arguments' => [ + 'name' => 'valid-pen', + 'type' => 'hidden', + 'value' => $this->validPen, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Name'), + 'id' => 'inp-name', + 'arguments' => [ + 'name' => 'name', + 'input_class' => 'flex-row', + 'type' => 'text', + 'value' => $this->name, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('Description'), + 'id' => 'inp-description', + 'arguments' => [ + 'name' => 'description', + 'input_class' => 'flex-row', + 'type' => 'textarea', + 'value' => $this->description, + 'return' => true, + ], + ]; + + $inputs[] = [ + 'label' => __('PEN'), + 'id' => 'inp-pen', + 'arguments' => [ + 'name' => 'pen', + 'input_class' => 'flex-row', + 'type' => 'text', + 'value' => $this->pen, + 'return' => true, + ], + ]; + + $availableButtons = []; + + $availableButtons[] = [ + 'arguments' => [ + 'name' => 'action_button', + 'label' => $formButtonLabel, + 'type' => 'submit', + 'value' => $formButtonValue, + 'attributes' => 'class="float-right '.$formButtonClass.'"', + 'return' => true, + ], + ]; + + if ($createNewTemplate === false) { + $availableButtons[] = [ + 'arguments' => [ + 'name' => 'add_components_button', + 'label' => __('Add components'), + 'type' => 'button', + 'attributes' => 'class="float-right sub cog"', + 'script' => 'showAddComponent();', + 'return' => true, + ], + ]; + } + + $inputs[] = [ + 'class' => 'action_button_list', + 'direct' => false, + 'wrapper' => 'div', + 'block_content' => $availableButtons, + ]; + + // Required for PEN field. + ui_require_jquery_file('tag-editor'); + ui_require_css_file('jquery.tag-editor'); + + if ($createNewTemplate === false) { + // Get the data. + $sql = sprintf( + 'SELECT npc.id_nc AS component_id, nc.name, nc.type, nc.description, nc.id_group AS `group`, nc.id_modulo AS `id_format`, ncg.name AS `group_name` + FROM tnetwork_profile_component AS npc, tnetwork_component AS nc + INNER JOIN tnetwork_component_group AS ncg ON ncg.id_sg = nc.id_group + WHERE npc.id_nc = nc.id_nc AND npc.id_np = %d', + $this->id_np + ); + $moduleBlocks = db_get_all_rows_sql($sql); + + if ($moduleBlocks) { + $blockTables = []; + // Build the information of the blocks. + foreach ($moduleBlocks as $block) { + if (key_exists($block['group'], $blockTables) === false) { + $blockTables[$block['group']] = [ + 'name' => $block['group_name'], + 'data' => [], + ]; + } + + $blockTables[$block['group']]['data'][] = [ + 'component_id' => $block['component_id'], + 'name' => $block['name'], + 'type' => $block['type'], + 'description' => $block['description'], + 'id_format' => $block['id_format'], + ]; + } + + if (count($blockTables) === 0) { + ui_print_info_message(__('No module blocks for this profile')); + } else { + foreach ($blockTables as $id_group => $blockTable) { + // Data with all components. + $blockData = $blockTable['data']; + // Creation of list of all components. + $blockComponentList = ''; + foreach ($blockData as $component) { + $blockComponentList .= $component['component_id'].','; + } + + $blockComponentList = chop($blockComponentList, ','); + // Title of Block. + $blockTitle = '
    '; + $blockTitle .= $blockTable['name']; + $blockTitle .= '
    '; + $blockTitle .= html_print_input_image( + 'del_block_'.$id_group.'_', + 'images/cross.png', + 1, + false, + true, + [ + 'title' => __('Delete this block'), + 'onclick' => 'if(confirm(\''.__('Do you want delete this block?').'\')){deleteModuleTemplate(\'block\',\''.$blockComponentList.'\')};return false;', + ] + ); + + $blockTitle .= '
    '; + + $table = new StdClasS(); + $table->class = 'databox data'; + $table->width = '75%'; + $table->styleTable = 'margin: 2em auto 0;border: 1px solid #ddd;background: white;'; + $table->rowid = []; + $table->data = []; + + $table->cellpadding = 0; + $table->cellspacing = 0; + $table->width = '100%'; + $table->class = 'info_table'; + + $table->head = []; + $table->head[0] = __('Module Name'); + $table->head[1] = ''.__('Format').''; + $table->head[2] = ''.__('Type').''; + $table->head[3] = __('Description'); + $table->head[4] = ''.__('Delete').''; + + $table->size = []; + $table->size[0] = '15%'; + $table->size[3] = '65%'; + $table->size[4] = '15%'; + + $table->align = []; + $table->align[4] = 'right'; + + $table->style = []; + $table->style[4] = 'padding-right:2em'; + + $table->data = []; + + foreach ($blockData as $module) { + $data[0] = ''.$module['name'].''; + switch ($module['id_format']) { + case MODULE_NETWORK: + $formatInfo = html_print_image( + 'images/network.png', + true, + ['title' => __('Network module')] + ); + break; + + case MODULE_WMI: + $formatInfo = html_print_image( + 'images/wmi.png', + true, + ['title' => __('WMI module')] + ); + break; + + case MODULE_PLUGIN: + $formatInfo = html_print_image( + 'images/plugin.png', + true, + ['title' => __('Plug-in module')] + ); + break; + + default: + $formatInfo = $module['id_format']; + break; + } + + $data[1] = html_print_div( + [ + 'style' => 'margin: 0 auto;width: 50%;', + 'content' => $formatInfo, + ], + true + ); + $data[2] = ui_print_moduletype_icon($module['type'], true); + $data[3] = mb_strimwidth(io_safe_output($module['description']), 0, 150, '...'); + $data[4] = html_print_input_image( + 'del_module_'.$module['component_id'].'_', + 'images/cross.png', + 1, + '', + true, + [ + 'title' => __('Delete this module'), + 'onclick' => 'if(confirm(\''.__('Do you want delete this module?').'\')){deleteModuleTemplate(\'module\','.$module['component_id'].')};return false;', + ] + ); + + array_push($table->data, $data); + } + + $content = html_print_table($table, true); + + $rawInputs .= ui_toggle($content, $blockTitle, '', '', false, true); + } + } + } else { + ui_print_info_message(__('No module blocks for this profile')); + } + } + + $this->printFormAsList( + [ + 'form' => $form, + 'inputs' => $inputs, + 'rawInputs' => $rawInputs, + true + ] + ); + + if ($createNewTemplate === false) { + echo ''; + echo ''; + } + + $this->printGoBackButton($this->baseUrl); + } + + + /** + * Loads JS and return code. + * + * @return string + */ + public function loadJS() + { + $str = ''; + + ob_start(); + ?> + + + '; + return $imgbase64; } } diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index b4d3011fdb..76e06c77df 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -722,6 +722,7 @@ function html_print_select( * @param string $style The string of style. * @param mixed $size Max elements showed in select or default (size=10) * @param integer $truncante_size Truncate size of the element, by default is set to GENERIC_SIZE_TEXT constant + * @param integer $class Class to apply. * * @return string HTML code if return parameter is true. */ @@ -738,7 +739,8 @@ function html_print_select_from_sql( $disabled=false, $style=false, $size=false, - $trucate_size=GENERIC_SIZE_TEXT + $trucate_size=GENERIC_SIZE_TEXT, + $class='' ) { global $config; @@ -770,7 +772,7 @@ function html_print_select_from_sql( $return, $multiple, $sort, - '', + $class, $disabled, $style, '', @@ -1087,7 +1089,7 @@ function html_print_extended_select_for_time( ob_start(); // Use the no_meta parameter because this image is only in the base console - echo '
    '; + echo '
    '; html_print_select( $fields, $uniq_name.'_select', @@ -1121,7 +1123,7 @@ function html_print_extended_select_for_time( echo '
    '; - echo '
    '; + echo '
    '; html_print_input_text($uniq_name.'_text', $selected, '', $size, 255, false, $readonly, false, '', $class); html_print_input_hidden($name, $selected, false, $uniq_name); @@ -1159,8 +1161,8 @@ function html_print_extended_select_for_time( $('#text-".$uniq_name."_text').val(seconds); adjustTextUnits('".$uniq_name."'); calculateSeconds('".$uniq_name."'); - $('#".$uniq_name."_manual').show(); - $('#".$uniq_name."_default').hide(); + $('#".$uniq_name."_manual').css('display', 'flex'); + $('#".$uniq_name."_default').css('display', 'none'); } "; $returnString = ob_get_clean(); @@ -1334,6 +1336,7 @@ function html_print_input_text_extended( 'onkeyup', 'required', 'autocomplete', + 'form', ]; $output = ''; + $output = '
    '; $output .= '
    '; $output .= '
    '; $output .= html_print_table($table, true); diff --git a/pandora_console/include/functions_treeview.php b/pandora_console/include/functions_treeview.php index 3217a544bf..32688a25ea 100755 --- a/pandora_console/include/functions_treeview.php +++ b/pandora_console/include/functions_treeview.php @@ -123,11 +123,11 @@ function treeview_printModuleTable($id_module, $server_data=false, $no_head=fals $row['data'] = $module_group; $table->data['module_group'] = $row; - // Description + // Description. $row = []; $row['title'] = __('Description'); $row['data'] = ui_print_truncate_text( - $module['descripcion'];, + $module['descripcion'], 'description', true, true, @@ -761,21 +761,25 @@ function treeview_printTable($id_agente, $server_data=[], $no_head=false) } } - // End of table advanced + // End of table advanced. $table_advanced = html_print_table($table, true); $table_advanced .= '
    '; ui_toggle($table_advanced, __('Advanced information')); if ($config['agentaccess']) { - $access_graph = '
    '; + $access_graph = '
    '; $access_graph .= graphic_agentaccess( $id_agente, SECONDS_1DAY, - true + false ); $access_graph .= '
    '; - ui_toggle($access_graph, __('Agent access rate (24h)')); + + ui_toggle( + $access_graph, + __('Agent access rate (24h)') + ); } $events_graph = '
    '; diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index f46089d735..0ce95daf78 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -2848,6 +2848,7 @@ function ui_print_status_sets( * [ * 'page' => 'operation/agentes/ver_agente', Target page. * 'interval' => 100 / $agent["intervalo"], Ask every interval seconds. + * 'simple' => 0, * 'data' => [ Data to be sent to target page. * 'id_agente' => $id_agente, * 'refresh_contact' => 1, @@ -2881,56 +2882,99 @@ function ui_progress( $text = $progress.'%'; } + $id = uniqid(); + ui_require_css_file('progress'); - $output .= ''; - $output .= ''; + $output .= ''; $output .= ''; if ($ajax !== false && is_array($ajax)) { - $output .= ''; + } else { + $output .= ''; + } } if (!$return) { @@ -3469,10 +3513,13 @@ function ui_print_datatable(array $parameters) ui_require_javascript_file('buttons.html5.min'); ui_require_javascript_file('buttons.print.min'); - $output = $include.$output; + if (isset($parameters['return']) && $parameters['return'] == true) { + // Compat. + $parameters['print'] = false; + } // Print datatable if needed. - if (isset($parameters['print']) === false || $parameters['print'] === false) { + if (isset($parameters['print']) === false || $parameters['print'] === true) { echo $output; } @@ -3673,8 +3720,8 @@ function ui_toggle( // Generate unique Id. $uniqid = uniqid(''); - $image_a = html_print_image($img_a, true, false, true); - $image_b = html_print_image($img_b, true, false, true); + $image_a = html_print_image($img_a, true, [ 'style' => 'object-fit: contain;' ], true); + $image_b = html_print_image($img_b, true, [ 'style' => 'object-fit: contain;' ], true); // Options. if ($hidden_default) { $style = 'display:none'; @@ -3698,6 +3745,7 @@ function ui_toggle( $original, true, [ + 'style' => 'object-fit: contain;', 'title' => $title, 'id' => 'image_'.$uniqid, ] diff --git a/pandora_console/include/javascript/jquery.caret.min.js b/pandora_console/include/javascript/jquery.caret.min.js new file mode 100644 index 0000000000..0f9ef48d6e --- /dev/null +++ b/pandora_console/include/javascript/jquery.caret.min.js @@ -0,0 +1,2 @@ +// http://code.accursoft.com/caret - 1.3.3 +!function(e){e.fn.caret=function(e){var t=this[0],n="true"===t.contentEditable;if(0==arguments.length){if(window.getSelection){if(n){t.focus();var o=window.getSelection().getRangeAt(0),r=o.cloneRange();return r.selectNodeContents(t),r.setEnd(o.endContainer,o.endOffset),r.toString().length}return t.selectionStart}if(document.selection){if(t.focus(),n){var o=document.selection.createRange(),r=document.body.createTextRange();return r.moveToElementText(t),r.setEndPoint("EndToEnd",o),r.text.length}var e=0,c=t.createTextRange(),r=document.selection.createRange().duplicate(),a=r.getBookmark();for(c.moveToBookmark(a);0!==c.moveStart("character",-1);)e++;return e}return t.selectionStart?t.selectionStart:0}if(-1==e&&(e=this[n?"text":"val"]().length),window.getSelection)n?(t.focus(),window.getSelection().collapse(t.firstChild,e)):t.setSelectionRange(e,e);else if(document.body.createTextRange)if(n){var c=document.body.createTextRange();c.moveToElementText(t),c.moveStart("character",e),c.collapse(!0),c.select()}else{var c=t.createTextRange();c.move("character",e),c.select()}return n||t.focus(),e}}(jQuery); diff --git a/pandora_console/include/javascript/jquery.tag-editor.js b/pandora_console/include/javascript/jquery.tag-editor.js new file mode 100644 index 0000000000..719ae04225 --- /dev/null +++ b/pandora_console/include/javascript/jquery.tag-editor.js @@ -0,0 +1,370 @@ +/* + jQuery tagEditor v1.0.21 + Copyright (c) 2014 Simon Steinberger / Pixabay + GitHub: https://github.com/Pixabay/jQuery-tagEditor + License: http://www.opensource.org/licenses/mit-license.php +*/ + +(function($){ + // auto grow input (stackoverflow.com/questions/931207) + $.fn.tagEditorInput=function(){var t=" ",e=$(this),n=parseInt(e.css("fontSize")),i=$("").css({position:"absolute",top:-9999,left:-9999,width:"auto",fontSize:e.css("fontSize"),fontFamily:e.css("fontFamily"),fontWeight:e.css("fontWeight"),letterSpacing:e.css("letterSpacing"),whiteSpace:"nowrap"}),s=function(){if(t!==(t=e.val())){i.text(t);var s=i.width()+n;20>s&&(s=20),s!=e.width()&&e.width(s)}};return i.insertAfter(e),e.bind("keyup keydown focus",s)}; + + // plugin with val as parameter for public methods + $.fn.tagEditor = function(options, val, blur){ + + // helper + function escape(tag) { + return tag.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); + } + + // build options dictionary with default values + var blur_result, o = $.extend({}, $.fn.tagEditor.defaults, options), selector = this; + + // store regex and default delimiter in options for later use + o.dregex = new RegExp('['+o.delimiter.replace('-', '\-')+']', 'g'); + + // public methods + if (typeof options == 'string') { + // depending on selector, response may contain tag lists of multiple editor instances + var response = []; + selector.each(function(){ + // the editor is the next sibling to the hidden, original field + var el = $(this), o = el.data('options'), ed = el.next('.tag-editor'); + if (options == 'getTags') + response.push({field: el[0], editor: ed, tags: ed.data('tags')}); + else if (options == 'addTag') { + if (o.maxTags && ed.data('tags').length >= o.maxTags) return false; + // insert new tag + $('
  •  '+o.delimiter[0]+'
  • ').appendTo(ed).find('.tag-editor-tag') + .html('').addClass('active').find('input').val(val).blur(); + if (!blur) ed.click(); + else $('.placeholder', ed).remove(); + } else if (options == 'removeTag') { + // trigger delete on matching tag, then click editor to create a new tag + $('.tag-editor-tag', ed).filter(function(){return $(this).text()==val;}).closest('li').find('.tag-editor-delete').click(); + if (!blur) ed.click(); + } else if (options == 'destroy') { + el.removeClass('tag-editor-hidden-src').removeData('options').off('focus.tag-editor').next('.tag-editor').remove(); + } + }); + return options == 'getTags' ? response : this; + } + + // delete selected tags on backspace, delete, ctrl+x + if (window.getSelection) $(document).off('keydown.tag-editor').on('keydown.tag-editor', function(e){ + if (e.which == 8 || e.which == 46 || e.ctrlKey && e.which == 88) { + try { + var sel = getSelection(), el = document.activeElement.tagName != 'INPUT' ? $(sel.getRangeAt(0).startContainer.parentNode).closest('.tag-editor') : 0; + } catch(e){ el = 0; } + if (sel.rangeCount > 0 && el && el.length) { + var tags = [], splits = sel.toString().split(el.prev().data('options').dregex); + for (i=0; i').insertAfter(el); + el.addClass('tag-editor-hidden-src') // hide original field + .data('options', o) // set data on hidden field + .on('focus.tag-editor', function(){ ed.click(); }); // simulate tabindex + + // add dummy item for min-height on empty editor + ed.append('
  •  
  • '); + + // markup for new tag + var new_tag = '
  •  '+o.delimiter[0]+'
  • '; + + // helper: update global data + function set_placeholder(){ + if (o.placeholder && !tag_list.length && !$('.deleted, .placeholder, input', ed).length) + ed.append('
  • '+o.placeholder+'
  • '); + } + + // helper: update global data + function update_globals(init){ + var old_tags = tag_list.toString(); + tag_list = $('.tag-editor-tag:not(.deleted)', ed).map(function(i, e) { + var val = $.trim($(this).hasClass('active') ? $(this).find('input').val() : $(e).text()); + if (val) return val; + }).get(); + ed.data('tags', tag_list); + el.val(tag_list.join(o.delimiter[0])); + // change callback except for plugin init + if (!init) if (old_tags != tag_list.toString()) o.onChange(el, ed, tag_list); + set_placeholder(); + } + + ed.click(function(e, closest_tag){ + var d, dist = 99999, loc; + + // do not create tag when user selects tags by text selection + if (window.getSelection && getSelection() != '') return; + + if (o.maxTags && ed.data('tags').length >= o.maxTags) { ed.find('input').blur(); return false; } + + blur_result = true + $('input:focus', ed).blur(); + if (!blur_result) return false; + blur_result = true + + // always remove placeholder on click + $('.placeholder', ed).remove(); + if (closest_tag && closest_tag.length) + loc = 'before'; + else { + // calculate tag closest to click position + $('.tag-editor-tag', ed).each(function(){ + var tag = $(this), to = tag.offset(), tag_x = to.left, tag_y = to.top; + if (e.pageY >= tag_y && e.pageY <= tag_y+tag.height()) { + if (e.pageX < tag_x) loc = 'before', d = tag_x - e.pageX; + else loc = 'after', d = e.pageX - tag_x - tag.width(); + if (d < dist) dist = d, closest_tag = tag; + } + }); + } + + if (loc == 'before') { + $(new_tag).insertBefore(closest_tag.closest('li')).find('.tag-editor-tag').click(); + } else if (loc == 'after') + $(new_tag).insertAfter(closest_tag.closest('li')).find('.tag-editor-tag').click(); + else // empty editor + $(new_tag).appendTo(ed).find('.tag-editor-tag').click(); + return false; + }); + + ed.on('click', '.tag-editor-delete', function(e){ + // delete icon is hidden when input is visible; place cursor near invisible delete icon on click + if ($(this).prev().hasClass('active')) { $(this).closest('li').find('input').caret(-1); return false; } + + var li = $(this).closest('li'), tag = li.find('.tag-editor-tag'); + if (o.beforeTagDelete(el, ed, tag_list, tag.text()) === false) return false; + tag.addClass('deleted').animate({width: 0}, o.animateDelete, function(){ li.remove(); set_placeholder(); }); + update_globals(); + return false; + }); + + // delete on right mouse click or ctrl+click + if (o.clickDelete) + ed.on('mousedown', '.tag-editor-tag', function(e){ + if (e.ctrlKey || e.which > 1) { + var li = $(this).closest('li'), tag = li.find('.tag-editor-tag'); + if (o.beforeTagDelete(el, ed, tag_list, tag.text()) === false) return false; + tag.addClass('deleted').animate({width: 0}, o.animateDelete, function(){ li.remove(); set_placeholder(); }); + update_globals(); + return false; + } + }); + + ed.on('click', '.tag-editor-tag', function(e){ + // delete on right click or ctrl+click -> exit + if (o.clickDelete && (e.ctrlKey || e.which > 1)) return false; + + if (!$(this).hasClass('active')) { + var tag = $(this).text(); + // guess cursor position in text input + var left_percent = Math.abs(($(this).offset().left - e.pageX)/$(this).width()), caret_pos = parseInt(tag.length*left_percent), + input = $(this).html('').addClass('active').find('input'); + input.data('old_tag', tag).tagEditorInput().focus().caret(caret_pos); + if (o.autocomplete) { + var aco = $.extend({}, o.autocomplete); + // extend user provided autocomplete select method + var ac_select = 'select' in aco ? o.autocomplete.select : ''; + aco.select = function(e, ui){ if (ac_select) ac_select(e, ui); setTimeout(function(){ + ed.trigger('click', [$('.active', ed).find('input').closest('li').next('li').find('.tag-editor-tag')]); + }, 20); }; + input.autocomplete(aco); + } + } + return false; + }); + + // helper: split into multiple tags, e.g. after paste + function split_cleanup(input){ + var li = input.closest('li'), sub_tags = input.val().replace(/ +/, ' ').split(o.dregex), + old_tag = input.data('old_tag'), old_tags = tag_list.slice(0), exceeded = false, cb_val; // copy tag_list + for (var i=0; i
     '+o.delimiter[0]+'
    '+escape(tag)+'
    '); + if (o.maxTags && old_tags.length >= o.maxTags) { exceeded = true; break; } + } + input.attr('maxlength', o.maxLength).removeData('old_tag').val('') + if (exceeded) input.blur(); else input.focus(); + update_globals(); + } + + ed.on('blur', 'input', function(e){ + e.stopPropagation(); + var input = $(this), old_tag = input.data('old_tag'), tag = $.trim(input.val().replace(/ +/, ' ').replace(o.dregex, o.delimiter[0])); + if (!tag) { + if (old_tag && o.beforeTagDelete(el, ed, tag_list, old_tag) === false) { + input.val(old_tag).focus(); + blur_result = false; + update_globals(); + return; + } + try { input.closest('li').remove(); } catch(e){} + if (old_tag) update_globals(); + } + else if (tag.indexOf(o.delimiter[0])>=0) { split_cleanup(input); return; } + else if (tag != old_tag) { + if (o.forceLowercase) tag = tag.toLowerCase(); + cb_val = o.beforeTagSave(el, ed, tag_list, old_tag, tag); + tag = cb_val || tag; + if (cb_val === false) { + if (old_tag) { + input.val(old_tag).focus(); + blur_result = false; + update_globals(); + return; + } + try { input.closest('li').remove(); } catch(e){} + if (old_tag) update_globals(); + } + // remove duplicates + else if (o.removeDuplicates) + $('.tag-editor-tag:not(.active)', ed).each(function(){ if ($(this).text() == tag) $(this).closest('li').remove(); }); + } + input.parent().html(escape(tag)).removeClass('active'); + if (tag != old_tag) update_globals(); + set_placeholder(); + }); + + var pasted_content; + ed.on('paste', 'input', function(e){ + $(this).removeAttr('maxlength'); + pasted_content = $(this); + setTimeout(function(){ split_cleanup(pasted_content); }, 30); + }); + + // keypress delimiter + var inp; + ed.on('keypress', 'input', function(e){ + if (o.delimiter.indexOf(String.fromCharCode(e.which))>=0) { + inp = $(this); + setTimeout(function(){ split_cleanup(inp); }, 20); + } + }); + + ed.on('keydown', 'input', function(e){ + var $t = $(this); + + // left/up key + backspace key on empty field + if ((e.which == 37 || !o.autocomplete && e.which == 38) && !$t.caret() || e.which == 8 && !$t.val()) { + var prev_tag = $t.closest('li').prev('li').find('.tag-editor-tag'); + if (prev_tag.length) prev_tag.click().find('input').caret(-1); + else if ($t.val() && !(o.maxTags && ed.data('tags').length >= o.maxTags)) $(new_tag).insertBefore($t.closest('li')).find('.tag-editor-tag').click(); + return false; + } + // right/down key + else if ((e.which == 39 || !o.autocomplete && e.which == 40) && ($t.caret() == $t.val().length)) { + var next_tag = $t.closest('li').next('li').find('.tag-editor-tag'); + if (next_tag.length) next_tag.click().find('input').caret(0); + else if ($t.val()) ed.click(); + return false; + } + // tab key + else if (e.which == 9) { + // shift+tab + if (e.shiftKey) { + var prev_tag = $t.closest('li').prev('li').find('.tag-editor-tag'); + if (prev_tag.length) prev_tag.click().find('input').caret(0); + else if ($t.val() && !(o.maxTags && ed.data('tags').length >= o.maxTags)) $(new_tag).insertBefore($t.closest('li')).find('.tag-editor-tag').click(); + // allow tabbing to previous element + else { + el.attr('disabled', 'disabled'); + setTimeout(function(){ el.removeAttr('disabled'); }, 30); + return; + } + return false; + // tab + } else { + var next_tag = $t.closest('li').next('li').find('.tag-editor-tag'); + if (next_tag.length) next_tag.click().find('input').caret(0); + else if ($t.val()) ed.click(); + else return; // allow tabbing to next element + return false; + } + } + // del key + else if (e.which == 46 && (!$.trim($t.val()) || ($t.caret() == $t.val().length))) { + var next_tag = $t.closest('li').next('li').find('.tag-editor-tag'); + if (next_tag.length) next_tag.click().find('input').caret(0); + else if ($t.val()) ed.click(); + return false; + } + // enter key + else if (e.which == 13) { + ed.trigger('click', [$t.closest('li').next('li').find('.tag-editor-tag')]); + + // trigger blur if maxTags limit is reached + if (o.maxTags && ed.data('tags').length >= o.maxTags) ed.find('input').blur(); + + return false; + } + // pos1 + else if (e.which == 36 && !$t.caret()) ed.find('.tag-editor-tag').first().click(); + // end + else if (e.which == 35 && $t.caret() == $t.val().length) ed.find('.tag-editor-tag').last().click(); + // esc + else if (e.which == 27) { + $t.val($t.data('old_tag') ? $t.data('old_tag') : '').blur(); + return false; + } + }); + + // create initial tags + var tags = o.initialTags.length ? o.initialTags : el.val().split(o.dregex); + for (var i=0; i= o.maxTags) break; + var tag = $.trim(tags[i].replace(/ +/, ' ')); + if (tag) { + if (o.forceLowercase) tag = tag.toLowerCase(); + tag_list.push(tag); + ed.append('
  •  '+o.delimiter[0]+'
    '+escape(tag)+'
  • '); + } + } + update_globals(true); // true -> no onChange callback + + // init sortable + if (o.sortable && $.fn.sortable) ed.sortable({ + distance: 5, cancel: '.tag-editor-spacer, input', helper: 'clone', + update: function(){ update_globals(); } + }); + }); + }; + + $.fn.tagEditor.defaults = { + initialTags: [], + maxTags: 0, + maxLength: 50, + delimiter: ',;', + placeholder: '', + forceLowercase: true, + removeDuplicates: true, + clickDelete: false, + animateDelete: 175, + sortable: true, // jQuery UI sortable + autocomplete: null, // options dict for jQuery UI autocomplete + + // callbacks + onChange: function(){}, + beforeTagSave: function(){}, + beforeTagDelete: function(){} + }; +}(jQuery)); diff --git a/pandora_console/include/javascript/jquery.tag-editor.min.js b/pandora_console/include/javascript/jquery.tag-editor.min.js new file mode 100644 index 0000000000..94293448f0 --- /dev/null +++ b/pandora_console/include/javascript/jquery.tag-editor.min.js @@ -0,0 +1,3 @@ +// jQuery tagEditor v1.0.21 +// https://github.com/Pixabay/jQuery-tagEditor +!function(t){t.fn.tagEditorInput=function(){var e=" ",i=t(this),a=parseInt(i.css("fontSize")),r=t("").css({position:"absolute",top:-9999,left:-9999,width:"auto",fontSize:i.css("fontSize"),fontFamily:i.css("fontFamily"),fontWeight:i.css("fontWeight"),letterSpacing:i.css("letterSpacing"),whiteSpace:"nowrap"}),l=function(){if(e!==(e=i.val())){r.text(e);var t=r.width()+a;20>t&&(t=20),t!=i.width()&&i.width(t)}};return r.insertAfter(i),i.bind("keyup keydown focus",l)},t.fn.tagEditor=function(e,a,r){function l(t){return t.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}var n,o=t.extend({},t.fn.tagEditor.defaults,e),c=this;if(o.dregex=new RegExp("["+o.delimiter.replace("-","-")+"]","g"),"string"==typeof e){var s=[];return c.each(function(){var i=t(this),l=i.data("options"),n=i.next(".tag-editor");if("getTags"==e)s.push({field:i[0],editor:n,tags:n.data("tags")});else if("addTag"==e){if(l.maxTags&&n.data("tags").length>=l.maxTags)return!1;t('
  •  '+l.delimiter[0]+'
  • ').appendTo(n).find(".tag-editor-tag").html('').addClass("active").find("input").val(a).blur(),r?t(".placeholder",n).remove():n.click()}else"removeTag"==e?(t(".tag-editor-tag",n).filter(function(){return t(this).text()==a}).closest("li").find(".tag-editor-delete").click(),r||n.click()):"destroy"==e&&i.removeClass("tag-editor-hidden-src").removeData("options").off("focus.tag-editor").next(".tag-editor").remove()}),"getTags"==e?s:this}return window.getSelection&&t(document).off("keydown.tag-editor").on("keydown.tag-editor",function(e){if(8==e.which||46==e.which||e.ctrlKey&&88==e.which){try{var a=getSelection(),r="INPUT"!=document.activeElement.tagName?t(a.getRangeAt(0).startContainer.parentNode).closest(".tag-editor"):0}catch(e){r=0}if(a.rangeCount>0&&r&&r.length){var l=[],n=a.toString().split(r.prev().data("options").dregex);for(i=0;i
    '+o.placeholder+"
    ")}function i(i){var a=c.toString();c=t(".tag-editor-tag:not(.deleted)",s).map(function(e,i){var a=t.trim(t(this).hasClass("active")?t(this).find("input").val():t(i).text());return a?a:void 0}).get(),s.data("tags",c),r.val(c.join(o.delimiter[0])),i||a!=c.toString()&&o.onChange(r,s,c),e()}function a(e){for(var a,n=e.closest("li"),d=e.val().replace(/ +/," ").split(o.dregex),g=e.data("old_tag"),f=c.slice(0),h=!1,u=0;u
     '+o.delimiter[0]+'
    '+l(v)+'
    '),o.maxTags&&f.length>=o.maxTags)){h=!0;break}e.attr("maxlength",o.maxLength).removeData("old_tag").val(""),h?e.blur():e.focus(),i()}var r=t(this),c=[],s=t("
      ').insertAfter(r);r.addClass("tag-editor-hidden-src").data("options",o).on("focus.tag-editor",function(){s.click()}),s.append('
    •  
    • ');var d='
    •  '+o.delimiter[0]+'
    • ';s.click(function(e,i){var a,r,l=99999;if(!window.getSelection||""==getSelection())return o.maxTags&&s.data("tags").length>=o.maxTags?(s.find("input").blur(),!1):(n=!0,t("input:focus",s).blur(),n?(n=!0,t(".placeholder",s).remove(),i&&i.length?r="before":t(".tag-editor-tag",s).each(function(){var n=t(this),o=n.offset(),c=o.left,s=o.top;e.pageY>=s&&e.pageY<=s+n.height()&&(e.pageXa&&(l=a,i=n))}),"before"==r?t(d).insertBefore(i.closest("li")).find(".tag-editor-tag").click():"after"==r?t(d).insertAfter(i.closest("li")).find(".tag-editor-tag").click():t(d).appendTo(s).find(".tag-editor-tag").click(),!1):!1)}),s.on("click",".tag-editor-delete",function(){if(t(this).prev().hasClass("active"))return t(this).closest("li").find("input").caret(-1),!1;var a=t(this).closest("li"),l=a.find(".tag-editor-tag");return o.beforeTagDelete(r,s,c,l.text())===!1?!1:(l.addClass("deleted").animate({width:0},o.animateDelete,function(){a.remove(),e()}),i(),!1)}),o.clickDelete&&s.on("mousedown",".tag-editor-tag",function(a){if(a.ctrlKey||a.which>1){var l=t(this).closest("li"),n=l.find(".tag-editor-tag");return o.beforeTagDelete(r,s,c,n.text())===!1?!1:(n.addClass("deleted").animate({width:0},o.animateDelete,function(){l.remove(),e()}),i(),!1)}}),s.on("click",".tag-editor-tag",function(e){if(o.clickDelete&&(e.ctrlKey||e.which>1))return!1;if(!t(this).hasClass("active")){var i=t(this).text(),a=Math.abs((t(this).offset().left-e.pageX)/t(this).width()),r=parseInt(i.length*a),n=t(this).html('').addClass("active").find("input");if(n.data("old_tag",i).tagEditorInput().focus().caret(r),o.autocomplete){var c=t.extend({},o.autocomplete),d="select"in c?o.autocomplete.select:"";c.select=function(e,i){d&&d(e,i),setTimeout(function(){s.trigger("click",[t(".active",s).find("input").closest("li").next("li").find(".tag-editor-tag")])},20)},n.autocomplete(c)}}return!1}),s.on("blur","input",function(d){d.stopPropagation();var g=t(this),f=g.data("old_tag"),h=t.trim(g.val().replace(/ +/," ").replace(o.dregex,o.delimiter[0]));if(h){if(h.indexOf(o.delimiter[0])>=0)return void a(g);if(h!=f)if(o.forceLowercase&&(h=h.toLowerCase()),cb_val=o.beforeTagSave(r,s,c,f,h),h=cb_val||h,cb_val===!1){if(f)return g.val(f).focus(),n=!1,void i();try{g.closest("li").remove()}catch(d){}f&&i()}else o.removeDuplicates&&t(".tag-editor-tag:not(.active)",s).each(function(){t(this).text()==h&&t(this).closest("li").remove()})}else{if(f&&o.beforeTagDelete(r,s,c,f)===!1)return g.val(f).focus(),n=!1,void i();try{g.closest("li").remove()}catch(d){}f&&i()}g.parent().html(l(h)).removeClass("active"),h!=f&&i(),e()});var g;s.on("paste","input",function(){t(this).removeAttr("maxlength"),g=t(this),setTimeout(function(){a(g)},30)});var f;s.on("keypress","input",function(e){o.delimiter.indexOf(String.fromCharCode(e.which))>=0&&(f=t(this),setTimeout(function(){a(f)},20))}),s.on("keydown","input",function(e){var i=t(this);if((37==e.which||!o.autocomplete&&38==e.which)&&!i.caret()||8==e.which&&!i.val()){var a=i.closest("li").prev("li").find(".tag-editor-tag");return a.length?a.click().find("input").caret(-1):!i.val()||o.maxTags&&s.data("tags").length>=o.maxTags||t(d).insertBefore(i.closest("li")).find(".tag-editor-tag").click(),!1}if((39==e.which||!o.autocomplete&&40==e.which)&&i.caret()==i.val().length){var l=i.closest("li").next("li").find(".tag-editor-tag");return l.length?l.click().find("input").caret(0):i.val()&&s.click(),!1}if(9==e.which){if(e.shiftKey){var a=i.closest("li").prev("li").find(".tag-editor-tag");if(a.length)a.click().find("input").caret(0);else{if(!i.val()||o.maxTags&&s.data("tags").length>=o.maxTags)return r.attr("disabled","disabled"),void setTimeout(function(){r.removeAttr("disabled")},30);t(d).insertBefore(i.closest("li")).find(".tag-editor-tag").click()}return!1}var l=i.closest("li").next("li").find(".tag-editor-tag");if(l.length)l.click().find("input").caret(0);else{if(!i.val())return;s.click()}return!1}if(!(46!=e.which||t.trim(i.val())&&i.caret()!=i.val().length)){var l=i.closest("li").next("li").find(".tag-editor-tag");return l.length?l.click().find("input").caret(0):i.val()&&s.click(),!1}if(13==e.which)return s.trigger("click",[i.closest("li").next("li").find(".tag-editor-tag")]),o.maxTags&&s.data("tags").length>=o.maxTags&&s.find("input").blur(),!1;if(36!=e.which||i.caret()){if(35==e.which&&i.caret()==i.val().length)s.find(".tag-editor-tag").last().click();else if(27==e.which)return i.val(i.data("old_tag")?i.data("old_tag"):"").blur(),!1}else s.find(".tag-editor-tag").first().click()});for(var h=o.initialTags.length?o.initialTags:r.val().split(o.dregex),u=0;u=o.maxTags);u++){var v=t.trim(h[u].replace(/ +/," "));v&&(o.forceLowercase&&(v=v.toLowerCase()),c.push(v),s.append('
    •  '+o.delimiter[0]+'
      '+l(v)+'
    • '))}i(!0),o.sortable&&t.fn.sortable&&s.sortable({distance:5,cancel:".tag-editor-spacer, input",helper:"clone",update:function(){i()}})})},t.fn.tagEditor.defaults={initialTags:[],maxTags:0,maxLength:50,delimiter:",;",placeholder:"",forceLowercase:!0,removeDuplicates:!0,clickDelete:!1,animateDelete:175,sortable:!0,autocomplete:null,onChange:function(){},beforeTagSave:function(){},beforeTagDelete:function(){}}}(jQuery); \ No newline at end of file diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index 9a9c8bcba0..c91339f0c6 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -837,8 +837,8 @@ function post_process_select_events(name) { */ function period_select_init(name, allow_zero) { // Manual mode is hidden by default - $("#" + name + "_manual").hide(); - $("#" + name + "_default").show(); + $("#" + name + "_manual").css("display", "none"); + $("#" + name + "_default").css("display", "flex"); // If the text input is empty, we put on it 5 minutes by default if ($("#text-" + name + "_text").val() == "") { @@ -852,8 +852,8 @@ function period_select_init(name, allow_zero) { } } else if ($("#text-" + name + "_text").val() == 0 && allow_zero != true) { $("#" + name + "_units option:last").prop("selected", false); - $("#" + name + "_manual").show(); - $("#" + name + "_default").hide(); + $("#" + name + "_manual").css("display", "flex"); + $("#" + name + "_default").css("display", "none"); } } @@ -941,13 +941,13 @@ function selectFirst(name) { */ function toggleBoth(name) { if ($("#" + name + "_default").css("display") == "none") { - $("#" + name + "_default").css("display", "inline"); + $("#" + name + "_default").css("display", "flex"); } else { $("#" + name + "_default").css("display", "none"); } if ($("#" + name + "_manual").css("display") == "none") { - $("#" + name + "_manual").css("display", "inline"); + $("#" + name + "_manual").css("display", "flex"); } else { $("#" + name + "_manual").css("display", "none"); } diff --git a/pandora_console/include/javascript/pandora_taskList.js b/pandora_console/include/javascript/pandora_taskList.js index a3f31cff96..0d0b1f8298 100644 --- a/pandora_console/include/javascript/pandora_taskList.js +++ b/pandora_console/include/javascript/pandora_taskList.js @@ -22,7 +22,7 @@ function progress_task_list(id, title) { autoOpen: false, modal: false, resizable: false, - draggable: false, + draggable: true, closeOnEscape: true, width: 800, height: 600, @@ -35,19 +35,23 @@ function progress_task_list(id, title) { // Function var. var handleFetchTaskList = function(err, data) { if (err) { + console.error(err); + } + if (data.error) { // TODO: Show info about the problem. + $elem.html(data.error); + } else { + $elem.html(data.html); } - $elem.html(data.html); if (!$elem.dialog("isOpen")) $elem.dialog("open"); - - if (data.status != -1) { - timeoutRef = setTimeout(function() { - xhr = fetchTaskList(id, handleFetchTaskList); - }, 3000); - } }; + if (!$elem.dialog("isOpen")) + timeoutRef = setInterval(function() { + xhr = fetchTaskList(id, handleFetchTaskList); + }, 3000); + xhr = fetchTaskList(id, handleFetchTaskList); } @@ -60,12 +64,13 @@ function progress_task_list(id, title) { function fetchTaskList(id, callback) { return jQuery.ajax({ data: { - page: "include/ajax/task_list.ajax", - progress_task_discovery: 1, + page: "godmode/servers/discovery", + wiz: "tasklist", + method: "progressTaskDiscovery", id: id }, type: "POST", - url: "ajax.php", + url: $("#ajax-url").val(), dataType: "json", success: function(data) { callback(null, data); @@ -95,12 +100,13 @@ function show_map(id, name) { jQuery.ajax({ data: { - page: "include/ajax/task_list.ajax", - showmap: 1, + page: "godmode/servers/discovery", + wiz: "tasklist", + method: "taskShowmap", id: id }, type: "POST", - url: "ajax.php", + url: $("#ajax-url").val(), dataType: "html", success: function(data) { $("#map_task") @@ -109,3 +115,106 @@ function show_map(id, name) { } }); } + +function show_review(id, name) { + load_modal({ + target: $("#task_review"), + form: "review", + url: $("#ajax-url").val(), + modal: { + title: "Review " + name, + ok: "OK", + cancel: "Cancel" + }, + ajax_callback: function(data) { + var title = $("#success-str").val(); + var text = ""; + var failed = 0; + try { + data = JSON.parse(data); + text = data["result"]; + } catch (err) { + title = $("#failed-str").val(); + text = err.message; + failed = 1; + } + if (!failed && data["error"] != undefined) { + title = $("#failed-str").val(); + text = data["error"]; + failed = 1; + } + if (data["report"] != undefined) { + data["report"].forEach(function(item) { + text += "
      " + item; + }); + } + + $("#msg").empty(); + $("#msg").html(text); + $("#msg").dialog({ + width: 450, + position: { + my: "center", + at: "center", + of: window, + collision: "fit" + }, + maxHeight: 400, + title: title, + buttons: [ + { + class: + "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", + text: "OK", + click: function(e) { + if (!failed) { + $(".ui-dialog-content").dialog("close"); + $("#task_review").empty(); + location.reload(); + } else { + $(this).dialog("close"); + } + } + } + ] + }); + }, + extradata: [ + { + name: "id", + value: id + }, + { + name: "wiz", + value: "tasklist" + } + ], + onshow: { + page: "godmode/servers/discovery", + method: "showTaskReview", + maxHeight: 800 + }, + onsubmit: { + page: "godmode/servers/discovery", + method: "parseTaskReview" + } + }); +} + +function force_task_run(url) { + window.location = url; +} + +function force_task(url, ask) { + if (ask != undefined) { + confirmDialog({ + title: ask.title, + message: ask.message, + onAccept: function() { + force_task_run(url); + } + }); + } else { + force_task_run(url); + } +} diff --git a/pandora_console/include/javascript/pandora_ui.js b/pandora_console/include/javascript/pandora_ui.js index 14804d7ab5..70ffd40f7f 100644 --- a/pandora_console/include/javascript/pandora_ui.js +++ b/pandora_console/include/javascript/pandora_ui.js @@ -319,6 +319,21 @@ function load_modal(settings) { contentType: false, data: data, success: function(data) { + if (settings.onshow.parser) { + data = settings.onshow.parser(data); + } else { + data = (function(d) { + try { + d = JSON.parse(d); + } catch (e) { + // Not JSON + return d; + } + if (d.error) return d.error; + + if (d.result) return d.result; + })(data); + } settings.target.html(data); if (settings.onload != undefined) { settings.onload(data); @@ -338,6 +353,12 @@ function load_modal(settings) { ? settings.onshow.maxHeight : "auto", overlay: settings.modal.overlay, + position: { + my: "top+20%", + at: "top", + of: window, + collision: "fit" + }, buttons: required_buttons, closeOnEscape: true, open: function() { @@ -386,6 +407,7 @@ function confirmDialog(settings) { "ui-widget ui-state-default ui-corner-all ui-button-text-only sub upd submit-cancel", click: function() { $(this).dialog("close"); + $(this).remove(); if (typeof settings.onDeny == "function") settings.onDeny(); } }, @@ -395,6 +417,7 @@ function confirmDialog(settings) { "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", click: function() { $(this).dialog("close"); + $(this).remove(); if (typeof settings.onAccept == "function") settings.onAccept(); } } diff --git a/pandora_console/include/javascript/simTree.js b/pandora_console/include/javascript/simTree.js new file mode 100644 index 0000000000..7dfdd35739 --- /dev/null +++ b/pandora_console/include/javascript/simTree.js @@ -0,0 +1,441 @@ +/** + * IMPORTANT. Official plugin does not allow string ids + * This modificated one yes. + */ +!(function(e) { + var t = {}; + function i(s) { + if (t[s]) return t[s].exports; + var n = (t[s] = { i: s, l: !1, exports: {} }); + return e[s].call(n.exports, n, n.exports, i), (n.l = !0), n.exports; + } + (i.m = e), + (i.c = t), + (i.d = function(e, t, s) { + i.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: s }); + }), + (i.r = function(e) { + "undefined" != typeof Symbol && + Symbol.toStringTag && + Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), + Object.defineProperty(e, "__esModule", { value: !0 }); + }), + (i.t = function(e, t) { + if ((1 & t && (e = i(e)), 8 & t)) return e; + if (4 & t && "object" == typeof e && e && e.__esModule) return e; + var s = Object.create(null); + if ( + (i.r(s), + Object.defineProperty(s, "default", { enumerable: !0, value: e }), + 2 & t && "string" != typeof e) + ) + for (var n in e) + i.d( + s, + n, + function(t) { + return e[t]; + }.bind(null, n) + ); + return s; + }), + (i.n = function(e) { + var t = + e && e.__esModule + ? function() { + return e.default; + } + : function() { + return e; + }; + return i.d(t, "a", t), t; + }), + (i.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t); + }), + (i.p = ""), + i((i.s = 0)); +})([ + function(e, t, i) { + "use strict"; + i.r(t); + i(1); + !(function(e, t) { + if (!e || !e.document) throw new Error("simTree need window"); + !(function(e) { + var t, + i = e.document, + s = { + linkParent: !1, + response: { + name: "name", + id: "id", + pid: "pid", + checked: "checked", + open: "open", + disabled: "disabled" + } + }, + n = function(e) { + throw new Error(e); + }, + a = function(e, t) { + return e.replace(/\{\{(.+?)\}\}/g, function(e, i) { + return t[i] ? t[i] : ""; + }); + }, + r = function e(t) { + if ( + ("undefined" == typeof $ && n("simTreeneed jquery"), + $.isPlainObject(t)) + ) { + if ((t.el || n("你没有传el"), !(this instanceof e))) + return new e(t); + (this.options = $.extend(!0, {}, s, t)), this.init(); + } + }, + d = [], + o = []; + (r.prototype = { + version: "0.0.2", + constructor: r, + on: function(e, t, i) { + var s, n; + return ( + (this.handles[e] = this.handles[e] || []), + (s = this.handles[e].isTriggered), + (n = this.handles[e].args), + $.isFunction(t) && + (!0 === i ? (this.handles[e] = [t]) : this.handles[e].push(t), + s && t.call(this, n)), + this + ); + }, + off: function(e) { + return (this.handles[e] = []), this; + }, + trigger: function(e, t) { + var i, s; + for ( + this.handles[e] = this.handles[e] || [], + i = 0, + s = this.handles[e].length, + this.handles[e].isTriggered = !0, + this.handles[e].args = t; + i < s; + i++ + ) + this.handles[e][i].call(this, t); + }, + init: function() { + var e = this.options, + t = e.data; + (this.handles = {}), + (this.$el = $(e.el)), + (this.data = t), + this.event(), + this.render(); + }, + dataCallback: function() { + var e = arguments; + 1 === e.length ? this.render(e[0]) : this.doRender(e[0], e[1]); + }, + parse: function(e) { + var t = this.options, + i = t.response, + s = [], + n = {}, + a = 0, + r = e.length, + d = i.id, + o = i.pid; + if (t.childNodeAsy) return e; + for (; a < r; a++) { + var h = e[a], + c = h[d]; + if (h.children) return e; + c && (n[c] = h); + } + for (a = 0; a < r; a++) { + var h = e[a], + l = h[o], + u = n[l]; + l && u ? (u.children || (u.children = [])).push(h) : s.push(h); + } + return s; + }, + render: function(e) { + var e = e || this.data; + $.isFunction(e) && e({}, this.dataCallback.bind(this)), + $.isArray(e) && ((e = this.parse(e)), this.doRender(this.$el, e)); + }, + doRender: function(e, t, s) { + var n, + r, + h, + c, + l, + u = this, + f = this.options, + p = f.response, + m = t.length, + g = 0, + v = p.id, + k = p.name, + s = s || 1, + C = + '{{text}}', + b = e === this.$el, + y = $(i.createElement("ul")), + w = f.childNodeAsy ? "asy" : ""; + for ( + f.check || + (C = C.replace('', "")); + g < m; + g++ + ) + (n = t[g]), + (r = i.createElement("li")), + (c = !!n.children), + (l = n[p.disabled]), + (r.innerHTML = a(C, { + asy: w, + text: n[k], + spreadIcon: c ? "sim-icon-r" : "hidden" + })), + r.setAttribute("data-level", s), + r.setAttribute("data-id", n[v]), + l && r.setAttribute("class", "disabled"), + (h = $(r)).data("data", n), + y.append(h), + c && this.doRender(h, n.children, s + 1), + n[p.checked] && d.push(n[v]), + n[p.open] && o.push(n[v]); + m && e.append(y), + b + ? (y.addClass("sim-tree"), + this.trigger("done", t), + $.each(o, function(e, t) { + u.expandNode(t); + }), + this.setSelected(d)) + : f.childNodeAsy && + (this.hideLoading(e.find(".sim-tree-spread")), + y.addClass("show")); + }, + event: function() { + var e = this; + this.$el.off("click").on("click", function(t) { + var i = $(t.target); + return ( + i.hasClass("sim-tree-spread") && e.spread.call(e, i), + i.hasClass("sim-tree-checkbox") && (i = i.parent()), + "a" === i[0].tagName.toLowerCase() && e.clickNode.call(e, i), + !1 + ); + }), + this.$el.on("selectstart", function() { + return !1; + }), + this.options.done && this.on("done", this.options.done), + this.options.onClick && this.on("click", this.options.onClick), + this.options.onChange && this.on("change", this.options.onChange), + this.options.onSearch && this.on("search", this.options.onSearch); + }, + spread: function(e) { + e.hasClass("sim-icon-r") + ? this.doSpread(e, !0) + : this.doSpread(e, !1); + }, + showLoading: function(e) { + e.addClass("sim-loading"); + }, + hideLoading: function(e) { + e.removeClass("sim-loading"); + }, + doSpread: function(e, t) { + var i = e.parent(), + s = i.children("ul"), + n = i.data("data"); + n.children && + (t + ? (e.removeClass("sim-icon-r").addClass("sim-icon-d"), + "asy" === e.data("type") && + $.isFunction(this.data) && + (this.showLoading(e), + this.data(i.data("data"), this.dataCallback.bind(this, i)), + e.data("type", "")), + s.addClass("show")) + : (e.removeClass("sim-icon-d").addClass("sim-icon-r"), + s.removeClass("show"))); + }, + clickNode: function(e) { + var i, + s, + n, + a = this, + r = e.parent(), + d = this.$el.find("li"), + o = d.length, + h = 0, + c = [], + l = !1; + if (!r.hasClass("disabled")) { + if (this.options.check) + for ( + l = !0, + this.doCheck(e.find(".sim-tree-checkbox")), + this.options.linkParent && + ((s = r.children("ul")), + (n = s.find(".sim-tree-checkbox")), + $.each(n, function() { + a.doCheck($(this), r.data("checked"), !0); + })); + h < o; + h++ + ) + !0 === (i = d.eq(h).data()).checked && c.push(i.data); + else + t && t.css("font-weight", "normal"), + e.css("font-weight", "bold"), + (t = e), + (i = r.data("data")), + (c = [i]), + (l = !this.sels || !(this.sels[0] === i)); + (this.sels = c), + this.trigger("click", c), + l && this.trigger("change", c); + } + }, + doCheck: function(e, t, i) { + var s = e.closest("li"), + n = s.data(); + void 0 === t && (t = !n.checked), + !0 === t + ? e.removeClass("sim-tree-semi").addClass("checked") + : !1 === t + ? e.removeClass("checked sim-tree-semi") + : "semi" === t && + e.removeClass("checked").addClass("sim-tree-semi"), + s.data("checked", t), + !0 === this.options.linkParent && !i && this.setParentCheck(s); + }, + setParentCheck: function(e) { + var t, + i = e.parent("ul"), + s = i.parent("li"), + n = i.children("li"), + a = s.find(">a .sim-tree-checkbox"), + r = [], + d = n.length; + s.length && + (e.find(">a .sim-tree-checkbox").hasClass("sim-tree-semi") + ? this.doCheck(a, "semi") + : ($.each(n, function() { + !0 === $(this).data("checked") && r.push($(this)); + }), + (t = r.length), + d === t && this.doCheck(a, !0), + t || this.doCheck(a, !1), + t >= 1 && t < d && this.doCheck(a, "semi"))); + }, + search: function(e) { + if (this.$el) { + var t, + i, + s, + e = $.trim(e), + n = this.$el.find("li"), + a = 0, + r = n.length, + d = [], + o = new RegExp(e, "i"); + for ( + n + .hide() + .children(".sim-tree-spread") + .addClass("hidden"); + a < r; + a++ + ) + (i = n.eq(a)), + (t = i.children("a").text()), + (s = i.data("data")), + e + ? -1 !== t.search(o) && + (1 !== parseInt(i.data("level")) && + this.expandNode(s[this.options.response.pid]), + i + .parents("li") + .add(i) + .show(), + d.push(i)) + : (i.show(), + s.children && + i.children(".sim-tree-spread").removeClass("hidden")); + this.trigger("search", e); + } + }, + expandNode: function(e) { + var t = e.addClass ? e : this.$el.find("[data-id='" + e + "']"), + i = t.data("data"), + s = i[this.options.response.pid], + n = t.children(".sim-tree-spread"), + a = parseInt(t.data("level")); + i.children && + n.length && + (n.removeClass("hidden"), this.doSpread(n, !0)), + 1 !== a && this.expandNode(s); + }, + setSelected: function(e) { + var t = this, + i = e, + s = [], + n = []; + ("string" != typeof i && "number" != typeof i) || (i = [i]), + $.isArray(i) && + (this.options.check || (i = [i[0]]), + $.each(i, function(e, i) { + var a = t.$el.find("[data-id='" + i + "']"), + r = a.children("a"), + d = r.children(".sim-tree-checkbox"), + o = a.data("data"); + if (!a.length) return !0; + d.length ? t.doCheck(d, !0) : r.css("font-weight", "bold"), + 1 !== parseInt(a.data("level")) && + t.expandNode(o[t.options.response.pid]), + s.push(o), + n.push(a[0]); + }), + (t.sels = s), + t.trigger("click", s)); + }, + getSelected: function() { + return this.sels; + }, + disableNode: function(e) { + var t = this, + i = e; + ("string" != typeof i && "number" != typeof i) || (i = [i]), + $.isArray(i) && + $.each(i, function(e, i) { + var s = t.$el.find("[data-id='" + i + "']"); + s.addClass("disabled"); + }); + }, + destroy: function() { + for (var e in (this.$el.html(""), this)) delete this[e]; + }, + refresh: function(e) { + this.$el.html(""), this.render(e); + } + }), + (e.simTree = r), + ($.fn.simTree = function(e) { + return (e = $.extend(!0, { el: this }, e)), r(e); + }); + })(e); + })("undefined" != typeof window ? window : void 0); + }, + function(e, t, i) {} +]); diff --git a/pandora_console/include/lib/Dashboard/Widgets/events_list.php b/pandora_console/include/lib/Dashboard/Widgets/events_list.php index 31e66dd3fe..1d0d4a3563 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/events_list.php +++ b/pandora_console/include/lib/Dashboard/Widgets/events_list.php @@ -416,7 +416,12 @@ class EventsListWidget extends Widget $filter['limit'] = $this->values['limit']; $filter['order'] = '`utimestamp` DESC'; - if ((int) $this->values['severity'] !== -1) { + if ((int) $this->values['severity'] === 20) { + $filter['criticity'] = [ + EVENT_CRIT_WARNING, + EVENT_CRIT_CRITICAL, + ]; + } else if ((int) $this->values['severity'] !== -1) { $filter['criticity'] = $this->values['severity']; } diff --git a/pandora_console/include/lib/Dashboard/Widgets/graph_module_histogram.php b/pandora_console/include/lib/Dashboard/Widgets/graph_module_histogram.php index 7e99294311..067bbef1fd 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/graph_module_histogram.php +++ b/pandora_console/include/lib/Dashboard/Widgets/graph_module_histogram.php @@ -309,12 +309,6 @@ class GraphModuleHistogramWidget extends Widget $size = parent::getSize(); // Desactive scroll bars only this item. - $output .= ''; $id_agent = $this->values['agentId']; $id_module = $this->values['moduleId']; $period = $this->values['period']; diff --git a/pandora_console/include/lib/Dashboard/Widgets/maps_made_by_user.php b/pandora_console/include/lib/Dashboard/Widgets/maps_made_by_user.php index baa6765789..f285abdc08 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/maps_made_by_user.php +++ b/pandora_console/include/lib/Dashboard/Widgets/maps_made_by_user.php @@ -206,9 +206,9 @@ class MapsMadeByUser extends Widget $fields = \visual_map_get_user_layouts($config['id_user'], true); - // Event Type. + // Visual console. $inputs[] = [ - 'label' => __('Event type'), + 'label' => __('Visual console'), 'arguments' => [ 'type' => 'select', 'fields' => $fields, diff --git a/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php b/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php index 9691c3e81a..65df0b83d4 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php +++ b/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php @@ -439,7 +439,7 @@ class SystemGroupStatusWidget extends Widget } } - $height = (count($result_groups) * 30); + $height = (count($table->data) * 30); $style = 'min-width:200px; min-height:'.$height.'px;'; $output = '
      '; if ($flag_groups === true) { diff --git a/pandora_console/include/styles/dashboards.css b/pandora_console/include/styles/dashboards.css index e77b016359..0db5cd6cb3 100644 --- a/pandora_console/include/styles/dashboards.css +++ b/pandora_console/include/styles/dashboards.css @@ -339,10 +339,8 @@ table.widget_maps_status tr td:first-child { table.widget_maps_status tr td a { font-family: "lato-lighter", "Open Sans", sans-serif; letter-spacing: 0.03pt; - font-size: 11pt; + font-size: 9pt; text-decoration: none; - color: #3f3f3f; - font-weight: bolder; } table.widget_maps_status tr td img { diff --git a/pandora_console/include/styles/discovery.css b/pandora_console/include/styles/discovery.css index fc5749b4a8..158a75a009 100644 --- a/pandora_console/include/styles/discovery.css +++ b/pandora_console/include/styles/discovery.css @@ -169,6 +169,7 @@ span.breadcrumb_link { form.discovery * { font-size: 10pt; + font-family: "lato", "Open Sans", sans-serif; } form.discovery .label_select b { diff --git a/pandora_console/include/styles/hostdevices.css b/pandora_console/include/styles/hostdevices.css index 461327705e..e378e24d97 100644 --- a/pandora_console/include/styles/hostdevices.css +++ b/pandora_console/include/styles/hostdevices.css @@ -1,3 +1,14 @@ /* * TODO: This may be at hostdevices.css */ + +select.select_multiple { + min-width: 500px; + width: 50%; + height: 250px; +} + +.indented select.select_multiple { + min-width: calc(500px - 1em); + width: calc(50% - 1em); +} diff --git a/pandora_console/include/styles/jquery.tag-editor.css b/pandora_console/include/styles/jquery.tag-editor.css new file mode 100644 index 0000000000..0823e50d2e --- /dev/null +++ b/pandora_console/include/styles/jquery.tag-editor.css @@ -0,0 +1,146 @@ +/* surrounding tag container */ +.tag-editor { + list-style-type: none; + padding: 0 5px 0 0; + margin: 0; + overflow: hidden; + border: 1px solid #eee; + cursor: text; + font: normal 14px sans-serif; + color: #555; + background: #fff; + line-height: 20px; +} + +/* core styles usually need no change */ +.tag-editor li { + display: block; + float: left; + overflow: hidden; + margin: 3px 0; +} +.tag-editor div { + float: left; + padding: 0 4px; +} +.tag-editor .placeholder { + padding: 0 8px; + color: #bbb; +} +.tag-editor .tag-editor-spacer { + padding: 0; + width: 8px; + overflow: hidden; + color: transparent; + background: none; +} +.tag-editor input { + vertical-align: inherit; + border: 0; + outline: none; + padding: 0; + margin: 0; + cursor: text; + font-family: inherit; + font-weight: inherit; + font-size: inherit; + font-style: inherit; + box-shadow: none; + background: none; + color: #444; +} +/* hide original input field or textarea visually to allow tab navigation */ +.tag-editor-hidden-src { + position: absolute !important; + left: -99999px; +} +/* hide IE10 "clear field" X */ +.tag-editor ::-ms-clear { + display: none; +} + +/* tag style */ +.tag-editor .tag-editor-tag { + padding-left: 5px; + color: #46799b; + background: #e0eaf1; + white-space: nowrap; + overflow: hidden; + cursor: pointer; + border-radius: 2px 0 0 2px; +} + +/* delete icon */ +.tag-editor .tag-editor-delete { + background: #e0eaf1; + cursor: pointer; + border-radius: 0 2px 2px 0; + padding-left: 3px; + padding-right: 4px; +} +.tag-editor .tag-editor-delete i { + line-height: 18px; + display: inline-block; +} +.tag-editor .tag-editor-delete i:before { + font-size: 16px; + color: #8ba7ba; + content: "×"; + font-style: normal; +} +.tag-editor .tag-editor-delete:hover i:before { + color: #d65454; +} +.tag-editor .tag-editor-tag.active + .tag-editor-delete, +.tag-editor .tag-editor-tag.active + .tag-editor-delete i { + visibility: hidden; + cursor: text; +} + +.tag-editor .tag-editor-tag.active { + background: none !important; +} + +/* jQuery UI autocomplete - code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css */ +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; + font-size: 14px; +} +.ui-front { + z-index: 9999; +} +.ui-menu { + list-style: none; + padding: 1px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px 0.4em; + line-height: 1.4; + min-height: 0; /* support: IE7 */ +} +.ui-widget-content { + border: 1px solid #bbb; + background: #fff; + color: #555; +} +.ui-widget-content a { + color: #46799b; +} +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + background: #e0eaf1; +} +.ui-helper-hidden-accessible { + display: none; +} diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 62984d075d..b9f3b2a1ed 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -628,6 +628,9 @@ select:-internal-list-box { .float-right { float: right; } +.invisible { + display: none; +} div#page { background: #fbfbfb; @@ -5647,6 +5650,11 @@ div#status_pie { .white_table_graph_header b { font-size: 10pt; font-weight: 600; + width: 100%; +} + +.white_table_graph_header div.white_table_header_checkbox { + float: right; } .white_table_graph_header div#bullets_modules { diff --git a/pandora_console/include/styles/pen.css b/pandora_console/include/styles/pen.css new file mode 100644 index 0000000000..72701bd01e --- /dev/null +++ b/pandora_console/include/styles/pen.css @@ -0,0 +1,38 @@ +ul.wizard li > label:not(.p-switch) { + width: auto; +} + +form.top-action-buttons ul.wizard { + display: flex; + flex-direction: row; +} + +ul.wizard li { + margin-right: 1em; +} + +form.modal ul.wizard li { + display: flex; + flex-direction: row; + width: 90%; + margin: 0 auto; + justify-items: center; +} + +form.modal ul.wizard li * { + flex: 1; +} + +ul.wizard li.flex-indep { + flex: 1; + margin: 0; +} + +div#div-form { + padding: 0 2em; +} + +div#div-form textarea { + width: 100%; + margin-top: 1em; +} diff --git a/pandora_console/include/styles/simTree.css b/pandora_console/include/styles/simTree.css new file mode 100644 index 0000000000..0cb03527c6 --- /dev/null +++ b/pandora_console/include/styles/simTree.css @@ -0,0 +1,124 @@ +.sim-tree { + list-style: none; + font-size: 14px; + color: #333; +} +.sim-tree ul, +.sim-tree li { + margin: 0; + padding: 0; +} +.sim-tree li { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + font-size: 0; +} +.sim-tree li ul { + display: none; + margin-left: 15px; +} +.sim-tree ul.show, +.sim-tree li.show { + display: block; +} +.sim-tree ul.none, +.sim-tree li.none { + display: none; +} +.sim-tree li.disabled > a { + color: #aaa; + cursor: not-allowed; +} +.sim-tree li.disabled > a .sim-tree-checkbox { + border-color: #eee; +} +.sim-tree a { + font-size: 14px; + color: #333; + text-decoration: none; + vertical-align: top; + line-height: 26px; +} +.sim-tree .sim-tree-spread { + width: 20px; + padding-left: 5px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.sim-tree .sim-tree-spread.hidden { + visibility: hidden; +} +.sim-tree .sim-tree-spread, +.sim-tree a { + display: inline-block; + height: 26px; + cursor: pointer; +} +.sim-tree .sim-loading { + background: url(data:image/gif;base64,R0lGODlhEAAQAMQQAObm5uLi4unp6dHR0cnJydfX1+jo6O/v7/Dw8NPT0/39/crKyvr6+uDg4MfHx////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFAAAQACwAAAAAEAAQAAAFXeAjPkiTjGgaLI6Tvs9BtPAIMPH8KgK5DDhZSlFYlFrAGIrYMrUcyRGzdapZr6jE02FAyZ6JxrOrEAVnjgaCRS6IkjLjo9F2PaDBwLJAu+NfAix2LQsAMCVVYQgoIQAh+QQFAAAQACwJAAAABwAHAAAFFGDSIE/5OM7SmKhjsK55vjIt32UIACH5BAUAABAALAoAAwAGAAoAAAUaICQqgggpxYKcheM0qOskZm0/eA7luMibvRAAIfkEBQAAEAAsCQAJAAcABwAABRXgcxBOmTwi6TRouiAoIwbtI9d4/oQAIfkEBQAAEAAsAwAKAAoABgAABRsgJI7MKD6POJQnKjpD60IODKFzvQD3nDQISAgAIfkEBQAAEAAsAAAJAAcABwAABRPgI45kSSrFWTgj6rCisLwk0iQhACH5BAUAABAALAAAAwAHAAoAAAUcIPRAJPmco4mm61m+cJk4tGNATX0ryGK/jVspBAAh+QQFAAAQACwAAAAABwAHAAAFFOAjjmRpPgBDIsugio3juGIiz2oIADs=) + center center no-repeat; +} +.sim-tree .sim-loading.sim-icon-d:before, +.sim-tree .sim-loading.sim-icon-r:before { + display: none; +} +.sim-tree .sim-icon-d:before, +.sim-tree .sim-icon-r:before { + content: ""; + display: inline-block; + width: 0; + height: 0; + border: 6px solid transparent; + vertical-align: top; + position: relative; +} +.sim-tree .sim-icon-r:before { + border-left-width: 8px; + border-left-color: #333; + top: 7px; +} +.sim-tree .sim-icon-d:before { + margin-left: -4px; + border-top-color: #333; + top: 10px; +} +.sim-tree .sim-tree-checkbox { + display: inline-block; + border: 1px solid #ccc; + height: 16px; + width: 16px; + border-radius: 3px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + text-align: center; + line-height: 16px; + background: #fff; + color: #fff; + vertical-align: middle; + margin-right: 6px; + margin-top: -2px; +} +.sim-tree .sim-tree-checkbox.sim-tree-semi, +.sim-tree .sim-tree-checkbox.checked { + border-color: #2b85e4; + background-color: #2b85e4; +} +.sim-tree .sim-tree-checkbox.sim-tree-semi { + position: relative; +} +.sim-tree .sim-tree-checkbox.sim-tree-semi:after { + content: ""; + display: block; + position: absolute; + width: 8px; + height: 2px; + background: #fff; + top: 6px; + left: 3px; +} +.sim-tree .sim-tree-checkbox.checked { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAAD///////////////////////////////////////////////////////////////////////8AAADY904BAAAAE3RSTlMAOiE8877cHQkXr9cZQvUc20NAbrhSVAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAA7SURBVAjXY2DADhiZEGxmFlYkNhs7KpuDE0mci5sHoYaXj5sHyOaHqOblE4CzGRgE+RBsBgYhfmxuAABcBQF5T7U3IwAAAABJRU5ErkJggg==); + background-repeat: no-repeat; + background-position: center center; +} diff --git a/pandora_console/include/styles/task_list.css b/pandora_console/include/styles/task_list.css index d3ffb5d546..01f7a82549 100644 --- a/pandora_console/include/styles/task_list.css +++ b/pandora_console/include/styles/task_list.css @@ -36,7 +36,77 @@ ul.progress_task_discovery { flex-direction: column; } +div.subtitle { + width: 100%; + margin-top: 40px; + text-align: center; +} + +div.subtitle span { + font-size: 1.9em; + font-family: "lato-bolder", "Open Sans", sans-serif; +} + +div.subtitle div.manage { + text-align: center; + padding-top: 2em; + padding-bottom: 1em; +} + +div.subtitle div.manage button { + font-size: 1.2em; + font-family: "lato", "Open Sans", sans-serif; + display: inline-block; + margin-right: 1em; + cursor: pointer; + text-align: left; + border-radius: 21px; + box-shadow: 0 0 10px -5px #888; + padding: 0.5em 1em; + border: 1px solid #ddd; + user-select: none; + color: #424242; +} + +div.subtitle .link.review { + margin: 15px 0 -30px; + display: block; + font-weight: bold; +} + +#msg ul li { + margin-left: 3em; +} + +li.added { + list-style: url("../../images/header_ready.png"); +} +li.removed { + list-style: url("../../images/header_down.png"); +} + +#msg ul { + list-style: url("../../images/header_ready.png"); +} + ul.progress_task_discovery li span { font-size: 9pt; margin-left: 20px; } + +.ui-dialog.ui-widget-content { + cursor: initial; +} + +span.link { + cursor: pointer; +} + +span.link.review { + font-weight: bold; +} + +#review { + padding-top: 2em; + padding-left: 6.7em; +} diff --git a/pandora_console/include/styles/wizard.css b/pandora_console/include/styles/wizard.css index 029addf5cb..3d66e165ff 100644 --- a/pandora_console/include/styles/wizard.css +++ b/pandora_console/include/styles/wizard.css @@ -2,7 +2,11 @@ * Discovery > Wizard css global style */ +#main > form.discovery.wizard > .white_box { + min-width: 1024px; +} ul.wizard { + list-style-type: none; } ul.wizard li { @@ -23,6 +27,100 @@ ul.wizard li > textarea { font-family: monospace; } -.hidden { +.wizard .hidden { display: none; } + +.wizard .indented { + margin-left: 1em; +} + +.wizard .std_input { + display: flex; + margin-bottom: 25px; + flex-wrap: wrap; + justify-content: space-between; +} + +.wizard .std_input > .label_select { + flex: 1 1 100%; +} +.wizard .std_input > * { + flex: 1 1 auto; + align-self: baseline; +} + +.wizard .inline_input.no-margin { + margin-bottom: 0px; +} +.wizard .inline_input { + display: flex; + margin-bottom: 25px; + flex-wrap: wrap; + justify-content: space-between; + align-items: baseline; +} + +.wizard .inline_input * { + flex: 1 1 auto; +} + +.wizard .discovery_inline_input { + display: flex; + align-content: end; + flex: 0; + align-self: flex-start; +} + +/* override tag-editor styles */ +.wizard .tag-editor.ui-sortable { + width: 450px; + display: inline-block; +} + +.wizard .tag-editor .tag-editor-tag { + padding: 5px; + color: #fff; + background: #82b92e; +} + +.wizard .tag-editor .tag-editor-delete i { + line-height: inherit; +} +.wizard .tag-editor .tag-editor-delete i:before { + color: #ccc; +} +.wizard .tag-editor .tag-editor-delete:hover i:before { + color: #fff; +} + +.wizard .tag-editor .tag-editor-delete { + padding: 5px; + background: #e63c52; +} + +.wizard .time_selection_container { + display: flex; + align-items: baseline; + justify-items: center; + align-content: space-between; + margin-top: 1em; +} + +.wizard #interval_manual_container #interval_manual > * { + flex: 1 1 auto; +} + +.wizard-column-levels { + float: left; + width: 33%; + text-align: center; +} + +.action_button_list { + height: 60px; +} + +.action_button_list li { + display: inline; +} diff --git a/pandora_console/install.php b/pandora_console/install.php index ec4b256695..26de845c43 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -129,7 +129,7 @@
      meta = is_metaconsole(); if (is_metaconsole()) { @@ -360,7 +362,10 @@ if (is_ajax()) { true ); - $tmp->data = format_numeric($tmp->data, 1); + $tmp->data = format_numeric( + $tmp->data, + $config['graph_precision'] + ); $tmp->instructions = events_get_instructions($item); diff --git a/pandora_console/operation/messages/message_edit.php b/pandora_console/operation/messages/message_edit.php index 039222436e..0b9bca18ad 100644 --- a/pandora_console/operation/messages/message_edit.php +++ b/pandora_console/operation/messages/message_edit.php @@ -127,17 +127,7 @@ if ($read_message) { ).' '.$user_name; } - $order = [ - "\r\n", - "\n", - "\r", - ]; - $replace = '
      '; - $parsed_message = str_replace( - $order, - $replace, - trim(io_safe_output($row['message'])) - ); + $parsed_message = nl2br(htmlspecialchars(trim(io_safe_output($row['message'])))); echo '
      '; echo '

      '.$parsed_message.'

      '; diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index 46c2707672..c36a64c969 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 200413 +%define release 200414 # 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 e357814f65..ea0486171b 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 200413 +%define release 200414 # 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 72726fb317..6843fd4f62 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 200413 +%define release 200414 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 6fbcb0ec2c..c698f0d6a9 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -773,14 +773,14 @@ CREATE TABLE IF NOT EXISTS `trecon_task` ( `name` varchar(100) NOT NULL default '', `description` varchar(250) NOT NULL default '', `subnet` text NOT NULL, - `id_network_profile` int(10) unsigned NOT NULL default '0', - `create_incident` tinyint(3) unsigned NOT NULL default '0', - `id_group` int(10) unsigned NOT NULL default '1', - `utimestamp` bigint(20) unsigned NOT NULL default '0', - `status` tinyint(4) NOT NULL default '0', - `interval_sweep` int(10) unsigned NOT NULL default '0', - `id_recon_server` int(10) unsigned NOT NULL default '0', - `id_os` tinyint(4) NOT NULL default '0', + `id_network_profile` text, + `review_mode` tinyint(1) unsigned NOT NULL default 1, + `id_group` int(10) unsigned NOT NULL default 1, + `utimestamp` bigint(20) unsigned NOT NULL default 0, + `status` tinyint(4) NOT NULL default 0, + `interval_sweep` int(10) unsigned NOT NULL default 0, + `id_recon_server` int(10) unsigned NOT NULL default 0, + `id_os` tinyint(4) NOT NULL default 0, `recon_ports` varchar(250) NOT NULL default '', `snmp_community` varchar(64) NOT NULL default 'public', `id_recon_script` int(10), @@ -788,31 +788,59 @@ CREATE TABLE IF NOT EXISTS `trecon_task` ( `field2` varchar(250) NOT NULL default '', `field3` varchar(250) NOT NULL default '', `field4` varchar(250) NOT NULL default '', - `os_detect` tinyint(1) unsigned default '0', - `resolve_names` tinyint(1) unsigned default '0', - `parent_detection` tinyint(1) unsigned default '0', - `parent_recursion` tinyint(1) unsigned default '0', - `disabled` tinyint(1) unsigned NOT NULL DEFAULT '0', + `os_detect` tinyint(1) unsigned default 0, + `resolve_names` tinyint(1) unsigned default 0, + `parent_detection` tinyint(1) unsigned default 0, + `parent_recursion` tinyint(1) unsigned default 0, + `disabled` tinyint(1) unsigned NOT NULL DEFAULT 0, `macros` TEXT, - `alias_as_name` tinyint(2) NOT NULL default '0', - `snmp_enabled` tinyint(1) unsigned default '0', - `vlan_enabled` tinyint(1) unsigned default '0', - `snmp_version` varchar(5) NOT NULL default '1', + `alias_as_name` tinyint(2) NOT NULL default 0, + `snmp_enabled` tinyint(1) unsigned default 0, + `vlan_enabled` tinyint(1) unsigned default 0, + `snmp_version` varchar(5) NOT NULL default 1, `snmp_auth_user` varchar(255) NOT NULL default '', `snmp_auth_pass` varchar(255) NOT NULL default '', `snmp_auth_method` varchar(25) NOT NULL default '', `snmp_privacy_method` varchar(25) NOT NULL default '', `snmp_privacy_pass` varchar(255) NOT NULL default '', `snmp_security_level` varchar(25) NOT NULL default '', - `wmi_enabled` tinyint(1) unsigned DEFAULT '0', + `wmi_enabled` tinyint(1) unsigned DEFAULT 0, `auth_strings` text, - `autoconfiguration_enabled` tinyint(1) unsigned default '0', + `auto_monitor` TINYINT(1) UNSIGNED DEFAULT 1, + `autoconfiguration_enabled` tinyint(1) unsigned default 0, `summary` text, `type` int NOT NULL default 0, + `subnet_csv` TINYINT(1) UNSIGNED DEFAULT 0, PRIMARY KEY (`id_rt`), KEY `recon_task_daemon` (`id_recon_server`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- ---------------------------------------------------------------------- +-- Table `tdiscovery_tmp` +-- ---------------------------------------------------------------------- +CREATE TABLE `tdiscovery_tmp_agents` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `label` varchar(600) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', + `data` MEDIUMTEXT, + `review_date` datetime DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `id_rt` (`id_rt`), + INDEX `label` (`label`), + CONSTRAINT `tdta_trt` FOREIGN KEY (`id_rt`) REFERENCES `trecon_task` (`id_rt`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE `tdiscovery_tmp_connections` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id_rt` int(10) unsigned NOT NULL, + `dev_1` text, + `dev_2` text, + `if_1` text, + `if_2` text, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- ---------------------------------------------------------------------- -- Table `tmodule_relationship` -- ---------------------------------------------------------------------- @@ -926,6 +954,28 @@ CREATE TABLE IF NOT EXISTS `tnetwork_profile_component` ( KEY `id_np` (`id_np`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- ---------------------------------------------------------------------- +-- Table `tpen` +-- ---------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tpen` ( + `pen` int(10) unsigned NOT NULL, + `manufacturer` TEXT, + `description` TEXT, + PRIMARY KEY (`pen`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ---------------------------------------------------------------------- +-- Table `tnetwork_profile_pen` +-- ---------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS `tnetwork_profile_pen` ( + `pen` int(10) unsigned NOT NULL, + `id_np` int(10) unsigned NOT NULL, + CONSTRAINT `fk_network_profile_pen_pen` FOREIGN KEY (`pen`) + REFERENCES `tpen` (`pen`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `fk_network_profile_pen_id_np` FOREIGN KEY (`id_np`) + REFERENCES `tnetwork_profile` (`id_np`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- ---------------------------------------------------------------------- -- Table `tnota` -- ---------------------------------------------------------------------- diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql index 1095a32cba..29c7b6b6c6 100644 --- a/pandora_console/pandoradb_data.sql +++ b/pandora_console/pandoradb_data.sql @@ -1594,3 +1594,123 @@ VALUES (254,6,848,943,0,0,'','white',19,3600,0,0,0,0,1,0,0,0,0,'line','down','','#FFFFFF',0,0,'default',0,0.000,0.000,0,0,'digital_1','time','Europe/Madrid',0,0), (255,5,846,941,0,0,'','white',19,3600,0,0,0,0,1,0,0,0,0,'line','down','','#FFFFFF',0,0,'default',0,0.000,0.000,0,0,'digital_1','time','Europe/Madrid',0,0) ; + +-- +-- Dumping data for table `tpen` +-- + +INSERT INTO `tpen` +VALUES + (9,'cisco','Cisco System'), + (11,'hp','Hewlett Packard'), + (2021,'general_snmp','U.C. Davis, ECE Dept. Tom'), + (2636,'juniper','Juniper Networks'), + (3375,'f5','F5 Labs'), + (8072,'general_snmp','Net SNMP'), + (12356,'fortinet','Fortinet') +; + +-- +-- Dumping data for table `tnetwork_profile` and `tnetwork_profile_pen` +-- + +SET @template_name = 'Network Management'; +SET @template_description = 'Basic network monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Network Management')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Cisco MIBS'; +SET @template_description = 'Cisco devices monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Cisco MIBS' OR g.name = 'Catalyst 2900')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 9)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Linux System'; +SET @template_description = 'Linux system monitoring template (SNMP)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); + +SET @module_group = 'Linux'; + +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Linux' OR g.name = 'UCD Mibs (Linux, UCD-SNMP)')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); +INSERT INTO tnetwork_profile_pen (pen, id_np) SELECT * FROM (SELECT p.pen pen, np.id_np id_np FROM tnetwork_profile np, tpen p WHERE np.name = @template_name AND (p.pen = 2021 OR p.pen = 2636)) AS tmp WHERE NOT EXISTS (SELECT pp.id_np FROM tnetwork_profile p, tnetwork_profile_pen pp WHERE p.id_np = pp.id_np AND p.name = @template_name); + +SET @template_name = 'Windows System'; +SET @template_description = 'Windows system monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Microsoft Windows' OR g.name = 'Windows System')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Hardware'; +SET @template_description = 'Windows hardware monitoring templae (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Hardware Layer')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Active Directory'; +SET @template_description = 'Active directory monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows AD' OR g.name = 'AD Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows IIS'; +SET @template_description = 'IIS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows IIS' OR g.name = 'IIS services')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Exchange'; +SET @template_description = 'Exchange monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Exchange' OR g.name = 'Exchange Services' OR g.name = 'Exchange TCP Ports')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows LDAP'; +SET @template_description = 'LDAP monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows LDAP')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MDSTC'; +SET @template_description = 'MDSTC monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows MSDTC')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Printers'; +SET @template_description = 'Windows printers monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows Printers')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows DNS'; +SET @template_description = 'Windows DNS monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Windows DNS' OR g.name = 'DNS Counters')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows MS SQL Server'; +SET @template_description = 'MS SQL Server monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MS SQL Server')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Oracle'; +SET @template_description = 'Oracle monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Oracle')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'MySQL'; +SET @template_description = 'MySQL monitoring template'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'MySQL')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); + +SET @template_name = 'Windows Antivirus'; +SET @template_description = 'Windows antivirus monitoring template (WMI)'; + +INSERT INTO tnetwork_profile (id_np, name, description) SELECT * FROM (SELECT '' id_np, @template_name name, @template_description description) AS tmp WHERE NOT EXISTS (SELECT id_np FROM tnetwork_profile WHERE name = @template_name); +INSERT INTO tnetwork_profile_component (id_nc, id_np) SELECT * FROM (SELECT c.id_nc id_nc, p.id_np id_np FROM tnetwork_profile p, tnetwork_component c, tnetwork_component_group g WHERE g.id_sg = c.id_group AND p.name = @template_name AND (g.name = 'Norton' OR g.name = 'Panda' OR g.name = 'McAfee' OR g.name = 'Bitdefender' OR g.name = 'BullGuard' OR g.name = 'AVG' OR g.name = 'Kaspersky')) AS tmp WHERE NOT EXISTS (SELECT pc.id_np FROM tnetwork_profile p, tnetwork_profile_component pc WHERE p.id_np = pc.id_np AND p.name = @template_name); \ No newline at end of file diff --git a/pandora_plugins/Autodiscover services/autodiscover.py b/pandora_plugins/Autodiscover services/autodiscover.py deleted file mode 100644 index 78a70cddba..0000000000 --- a/pandora_plugins/Autodiscover services/autodiscover.py +++ /dev/null @@ -1,398 +0,0 @@ -#!/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 c05ca1876b..3f9a16fafa 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.744-200413 +Version: 7.0NG.744-200414 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 8632c7a578..cc120882c3 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-200413" +pandora_version="7.0NG.744-200414" package_cpan=0 package_pandora=1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index fd90a0d379..78d7a80081 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 = "200413"; +my $pandora_build = "200414"; 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 b41aec461e..b395ec9574 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -270,7 +270,9 @@ our @EXPORT = qw( pandora_delete_custom_graph pandora_edit_custom_graph notification_set_targets - ); + notification_get_users + notification_get_groups +); # Some global variables our @DayNames = qw(sunday monday tuesday wednesday thursday friday saturday); @@ -1646,6 +1648,17 @@ sub pandora_process_module ($$$$$$$$$;$) { "' for agent " . (defined ($agent) && $agent ne '' ? "'" . safe_output($agent->{'nombre'}) . "'" : 'ID ' . $module->{'id_agente'}) . ".", 10); + + # Ensure default values. + $module->{'min_ff_event'} = 0 unless defined($module->{'min_ff_event'}); + $module->{'ff_timeout'} = 0 unless defined($module->{'ff_timeout'}); + $module->{'module_interval'} = 0 unless defined($module->{'module_interval'}); + + if (ref($agent) eq 'HASH') { + if (!defined($agent->{'interval'}) && defined($agent->{'interval'})) { + $agent->{'intervalo'} = $agent->{'interval'}; + } + } # Get agent information if (! defined ($agent) || $agent eq '') { @@ -3134,6 +3147,8 @@ sub pandora_create_module_from_network_component ($$$$) { pandora_create_module_tags ($pa_config, $dbh, $module_id, $component_tags); logger($pa_config, 'Creating module ' . safe_output ($component->{'nombre'}) . " (ID $module_id) for agent $addr from network component.", 10); + + return $module_id; } ########################################################################## @@ -3141,7 +3156,7 @@ sub pandora_create_module_from_network_component ($$$$) { ########################################################################## sub pandora_create_module_from_hash ($$$) { my ($pa_config, $parameters, $dbh) = @_; - + logger($pa_config, "Creating module '$parameters->{'nombre'}' for agent ID $parameters->{'id_agente'}.", 10); @@ -3172,8 +3187,12 @@ sub pandora_create_module_from_hash ($$$) { } # Encrypt SNMP v3 passwords. - if ($parameters->{'id_tipo_modulo'} >= 15 && $parameters->{'id_tipo_modulo'} <= 18 && - $parameters->{'tcp_send'} eq '3') { + if (defined($parameters->{'tcp_send'}) + && $parameters->{'tcp_send'} eq '3' + && defined($parameters->{'id_tipo_modulo'}) + && $parameters->{'id_tipo_modulo'} >= 15 + && $parameters->{'id_tipo_modulo'} <= 18 + ) { $parameters->{'custom_string_2'} = pandora_input_password($pa_config, $parameters->{'custom_string_2'}); } @@ -3181,7 +3200,11 @@ sub pandora_create_module_from_hash ($$$) { 'tagente_modulo', $parameters); my $status = 4; - if (defined ($parameters->{'id_tipo_modulo'}) && ($parameters->{'id_tipo_modulo'} == 21 || $parameters->{'id_tipo_modulo'} == 22 || $parameters->{'id_tipo_modulo'} == 23)) { + if (defined ($parameters->{'id_tipo_modulo'}) + && ($parameters->{'id_tipo_modulo'} == 21 + || $parameters->{'id_tipo_modulo'} == 22 + || $parameters->{'id_tipo_modulo'} == 23) + ) { $status = 0; } @@ -3333,7 +3356,7 @@ sub pandora_create_agent ($$$$$$$$$$;$$$$$$$$$$) { $agent_mode = 1 unless defined($agent_mode); $alias = $agent_name unless defined($alias); - $description = "Created by $server_name" unless ($description ne ''); + $description = "Created by $server_name" unless (defined($description) && $description ne ''); my ($columns, $values) = db_insert_get_values ({ 'nombre' => safe_input($agent_name), 'direccion' => $address, 'comentarios' => $description, @@ -6295,6 +6318,63 @@ sub notification_set_targets { return 1; } +########################################################################## + +=head2 C<< notification_get_users (I<$dbh>, I<$source>) >> +Get targets for given sources +=cut + +########################################################################## +sub notification_get_users { + my ($dbh, $source) = @_; + + my @results = get_db_rows( + $dbh, + 'SELECT id_user + FROM tnotification_source_user nsu + INNER JOIN tnotification_source ns ON nsu.id_source=ns.id + WHERE ns.description = ? + ', + safe_input($source) + ); + + @results = map { + if(ref($_) eq 'HASH') { $_->{'id_user'} } + else {} + } @results; + + return @results; +} + +########################################################################## + +=head2 C<< notification_get_groups (I<$dbh>, I<$source>) >> +Get targets for given sources +=cut + +########################################################################## +sub notification_get_groups { + my ($dbh, $source) = @_; + + my @results = get_db_rows( + $dbh, + 'SELECT id_group + FROM tnotification_source_group nsg + INNER JOIN tnotification_source ns ON nsg.id_source=ns.id + WHERE ns.description = ? + ', + safe_input($source) + ); + + @results = map { + if(ref($_) eq 'HASH') { $_->{'id_group'} } + else {} + } @results; + + return @results; +} + + # End of function declaration # End of defined Code diff --git a/pandora_server/lib/PandoraFMS/DB.pm b/pandora_server/lib/PandoraFMS/DB.pm index 63c756e5ae..e5c63615e0 100644 --- a/pandora_server/lib/PandoraFMS/DB.pm +++ b/pandora_server/lib/PandoraFMS/DB.pm @@ -20,6 +20,7 @@ package PandoraFMS::DB; use strict; use warnings; use DBI; +use Carp qw/croak/; use lib '/usr/lib/perl5'; use PandoraFMS::Tools; @@ -80,6 +81,8 @@ our @EXPORT = qw( get_module_id get_module_name get_nc_profile_name + get_pen_templates + get_nc_profile_advanced get_os_id get_os_name get_plugin_id @@ -656,6 +659,48 @@ sub get_nc_profile_name ($$) { return get_db_value ($dbh, "SELECT * FROM tnetwork_profile WHERE id_np = ?", $nc_id); } +########################################################################## +## Return all network component's profile ids matching given PEN. +########################################################################## +sub get_pen_templates($$) { + my ($dbh, $pen) = @_; + + my @results = get_db_rows( + $dbh, + 'SELECT t.`id_np` + FROM `tnetwork_profile` t + INNER JOIN `tnetwork_profile_pen` pp ON pp.`id_np` = t.`id_np` + INNER JOIN `tpen` p ON pp.pen = p.pen + WHERE p.`pen` = ?', + $pen + ); + + @results = map { + if (ref($_) eq 'HASH') { $_->{'id_np'} } + else {} + } @results; + + + return @results; +} + +########################################################################## +## Return a network component's profile data and pen list, given its ID. +########################################################################## +sub get_nc_profile_advanced($$) { + my ($dbh, $id_nc) = @_; + return get_db_single_row( + $dbh, + 'SELECT t.*,GROUP_CONCAT(p.pen) AS "pen" + FROM `tnetwork_profile` t + LEFT JOIN `tnetwork_profile_pen` pp ON t.id_np = pp.id_np + LEFT JOIN `tpen` p ON pp.pen = p.pen + WHERE t.`id_np` = ? + GROUP BY t.`id_np`', + $id_nc + ); +} + ########################################################################## ## Return user profile ID given the user id, group id and profile id. ########################################################################## @@ -894,7 +939,7 @@ sub db_insert ($$$;@) { $insert_id = $dbh->{'mysql_insertid'}; } else { - die($exception); + croak (join(', ', @_)); } } @@ -917,7 +962,7 @@ sub db_update ($$;@) { $rows = $dbh->do($query, undef, @values); } else { - die($exception); + croak (join(', ', @_)); } } @@ -1163,7 +1208,7 @@ sub db_do ($$;@) { $dbh->do($query, undef, @values); } else { - die($exception); + croak (join(', ', @_)); } } } diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm index 87b1df711e..903a9014c3 100644 --- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm +++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm @@ -1,8 +1,8 @@ package PandoraFMS::DiscoveryServer; -########################################################################## +################################################################################ # Pandora FMS Discovery Server. # Pandora FMS. the Flexible Monitoring System. http://www.pandorafms.org -########################################################################## +################################################################################ # Copyright (c) 2005-2009 Artica Soluciones Tecnologicas S.L # # This program is free software; you can redistribute it and/or @@ -15,7 +15,7 @@ package PandoraFMS::DiscoveryServer; # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -########################################################################## +################################################################################ use strict; use warnings; @@ -40,9 +40,6 @@ use PandoraFMS::ProducerConsumerServer; use PandoraFMS::GIS; use PandoraFMS::Recon::Base; -# Patched Nmap::Parser. See http://search.cpan.org/dist/Nmap-Parser/. -use PandoraFMS::NmapParser; - # Inherits from PandoraFMS::ProducerConsumerServer our @ISA = qw(PandoraFMS::ProducerConsumerServer); @@ -54,408 +51,862 @@ my $TaskSem :shared; # IDs from tconfig_os. use constant { - OS_OTHER => 10, - OS_ROUTER => 17, - OS_SWITCH => 18, - STEP_SCANNING => 1, - STEP_AFT => 2, - STEP_TRACEROUTE => 3, - STEP_GATEWAY => 4, - STEP_STATISTICS => 1, - STEP_APP_SCAN => 2, - STEP_CUSTOM_QUERIES => 3, - DISCOVERY_HOSTDEVICES => 0, - DISCOVERY_HOSTDEVICES_CUSTOM => 1, - DISCOVERY_CLOUD_AWS => 2, - DISCOVERY_APP_VMWARE => 3, - DISCOVERY_APP_MYSQL => 4, - DISCOVERY_APP_ORACLE => 5, - DISCOVERY_CLOUD_AWS_EC2 => 6, - DISCOVERY_CLOUD_AWS_RDS => 7, - DISCOVERY_CLOUD_AZURE_COMPUTE => 8, - DISCOVERY_DEPLOY_AGENTS => 9, - DISCOVERY_APP_SAP => 10, + OS_OTHER => 10, + OS_ROUTER => 17, + OS_SWITCH => 18, + STEP_SCANNING => 1, + STEP_AFT => 2, + STEP_TRACEROUTE => 3, + STEP_GATEWAY => 4, + STEP_MONITORING => 5, + STEP_PROCESSING => 6, + STEP_STATISTICS => 1, + STEP_APP_SCAN => 2, + STEP_CUSTOM_QUERIES => 3, + DISCOVERY_HOSTDEVICES => 0, + DISCOVERY_HOSTDEVICES_CUSTOM => 1, + DISCOVERY_CLOUD_AWS => 2, + DISCOVERY_APP_VMWARE => 3, + DISCOVERY_APP_MYSQL => 4, + DISCOVERY_APP_ORACLE => 5, + DISCOVERY_CLOUD_AWS_EC2 => 6, + DISCOVERY_CLOUD_AWS_RDS => 7, + DISCOVERY_CLOUD_AZURE_COMPUTE => 8, + DISCOVERY_DEPLOY_AGENTS => 9, + DISCOVERY_APP_SAP => 10, + DISCOVERY_REVIEW => 0, + DISCOVERY_STANDARD => 1, + DISCOVERY_RESULTS => 2, }; -######################################################################################## +################################################################################ # Discovery Server class constructor. -######################################################################################## +################################################################################ sub new ($$$$$$) { - my ($class, $config, $dbh) = @_; - - return undef unless (defined($config->{'reconserver'}) && $config->{'reconserver'} == 1) - || (defined($config->{'discoveryserver'}) && $config->{'discoveryserver'} == 1); - - if (! -e $config->{'nmap'}) { - logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); - print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); - return undef; - } + my ($class, $config, $dbh) = @_; + + return undef unless (defined($config->{'reconserver'}) && $config->{'reconserver'} == 1) + || (defined($config->{'discoveryserver'}) && $config->{'discoveryserver'} == 1); + + if (! -e $config->{'nmap'}) { + logger ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); + print_message ($config, ' [E] ' . $config->{'nmap'} . " needed by " . $config->{'rb_product_name'} . " Discovery Server not found.", 1); + return undef; + } - # Initialize semaphores and queues - @TaskQueue = (); - %PendingTasks = (); - $Sem = Thread::Semaphore->new; - $TaskSem = Thread::Semaphore->new (0); - - # Restart automatic recon tasks. - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0', - get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); + # Initialize semaphores and queues + @TaskQueue = (); + %PendingTasks = (); + $Sem = Thread::Semaphore->new; + $TaskSem = Thread::Semaphore->new (0); + + # Restart automatic recon tasks. + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = 0 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep > 0', + get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); - # Reset (but do not restart) manual recon tasks. - db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0', - get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); + # Reset (but do not restart) manual recon tasks. + db_do ($dbh, 'UPDATE trecon_task SET status = -1 WHERE id_recon_server = ? AND status <> -1 AND interval_sweep = 0', + get_server_id ($dbh, $config->{'servername'}, DISCOVERYSERVER)); - # Call the constructor of the parent class - my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh); - - bless $self, $class; - return $self; + # Call the constructor of the parent class + my $self = $class->SUPER::new($config, DISCOVERYSERVER, \&PandoraFMS::DiscoveryServer::data_producer, \&PandoraFMS::DiscoveryServer::data_consumer, $dbh); + + bless $self, $class; + return $self; } -############################################################################### +################################################################################ # Run. -############################################################################### +################################################################################ sub run ($) { - my $self = shift; - my $pa_config = $self->getConfig (); - my $dbh = $self->getDBH(); - - print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1); - my $threads = $pa_config->{'recon_threads'}; + my $self = shift; + my $pa_config = $self->getConfig (); + my $dbh = $self->getDBH(); + + print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Discovery Server.", 1); + my $threads = $pa_config->{'recon_threads'}; - # Use hightest value - if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) { - $threads = $pa_config->{'discovery_threads'}; - } - $self->setNumThreads($threads); - $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem); + # Use hightest value + if ($pa_config->{'discovery_threads'} > $pa_config->{'recon_threads'}) { + $threads = $pa_config->{'discovery_threads'}; + } + $self->setNumThreads($threads); + $self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem); } -############################################################################### +################################################################################ # Data producer. -############################################################################### +################################################################################ sub data_producer ($) { - my $self = shift; - my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); - - my @tasks; - - my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ()); - return @tasks unless defined ($server_id); - - # Manual tasks have interval_sweep = 0 - # Manual tasks are "forced" like the other, setting the utimestamp to 1 - # By default, after create a tasks it takes the utimestamp to 0 - # Status -1 means "done". - my @rows; - if (pandora_is_master($pa_config) == 0) { - @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task - WHERE id_recon_server = ? - AND disabled = 0 - AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) - OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id); - } else { - @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task - WHERE (id_recon_server = ? OR id_recon_server = ANY(SELECT id_server FROM tserver WHERE status = 0 AND server_type = ?)) - AND disabled = 0 - AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) - OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER); - } + my $self = shift; + my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); + + my @tasks; + + my $server_id = get_server_id ($dbh, $pa_config->{'servername'}, $self->getServerType ()); + return @tasks unless defined ($server_id); + + # Manual tasks have interval_sweep = 0 + # Manual tasks are "forced" like the other, setting the utimestamp to 1 + # By default, after create a tasks it takes the utimestamp to 0 + # Status -1 means "done". + my @rows; + if (pandora_is_master($pa_config) == 0) { + @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task + WHERE id_recon_server = ? + AND disabled = 0 + AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) + OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id); + } else { + @rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task + WHERE (id_recon_server = ? OR id_recon_server = ANY(SELECT id_server FROM tserver WHERE status = 0 AND server_type = ?)) + AND disabled = 0 + AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1) + OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER); + } - foreach my $row (@rows) { - - # Update task status - update_recon_task ($dbh, $row->{'id_rt'}, 1); - - push (@tasks, $row->{'id_rt'}); - } + foreach my $row (@rows) { - return @tasks; + # Update task status + update_recon_task ($dbh, $row->{'id_rt'}, 1); + + push (@tasks, $row->{'id_rt'}); + } + + return @tasks; } -############################################################################### +################################################################################ # Data consumer. -############################################################################### +################################################################################ sub data_consumer ($$) { - my ($self, $task_id) = @_; - my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); + my ($self, $task_id) = @_; + my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); - # Get server id. - my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType()); + # Get server id. + my $server_id = get_server_id($dbh, $pa_config->{'servername'}, $self->getServerType()); - # Get recon task data - my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id); - return -1 unless defined ($task); + # Get recon task data + my $task = get_db_single_row ($dbh, 'SELECT * FROM trecon_task WHERE id_rt = ?', $task_id); + return -1 unless defined ($task); - # Is it a recon script? - if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) { - exec_recon_script ($pa_config, $dbh, $task); - return; - } else { - logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10); + # Is it a recon script? + if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) { + exec_recon_script ($pa_config, $dbh, $task); + return; + } else { + logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10); + } + + eval { + my @subnets = split(/,/, safe_output($task->{'subnet'})); + my @communities = split(/,/, safe_output($task->{'snmp_community'})); + my @auth_strings = (); + if(defined($task->{'auth_strings'})) { + @auth_strings = split(/,/, safe_output($task->{'auth_strings'})); } - eval { - my @subnets = split(/,/, safe_output($task->{'subnet'})); - my @communities = split(/,/, safe_output($task->{'snmp_community'})); - my @auth_strings = (); - if(defined($task->{'auth_strings'})) { - @auth_strings = split(/,/, safe_output($task->{'auth_strings'})); - } + my $main_event = pandora_event($pa_config, + "[Discovery] Execution summary", + $task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh + ); - my $main_event = pandora_event($pa_config, "[Discovery] Execution summary",$task->{'id_group'}, 0, 0, 0, 0, 'system', 0, $dbh); - - my %cnf_extra; - - my $r = enterprise_hook('discovery_generate_extra_cnf',[$pa_config, $dbh, $task, \%cnf_extra]); - if (defined($r) && $r eq 'ERR') { - # Could not generate extra cnf, skip this task. - return; - } - - - if ($task->{'type'} == DISCOVERY_APP_SAP) { - # SAP TASK, retrieve license. - $task->{'sap_license'} = pandora_get_config_value( - $dbh, - 'sap_license' - ); - - # Retrieve credentials for task (optional). - if (defined($task->{'auth_strings'}) - && $task->{'auth_strings'} ne '' - ) { - my $key = credential_store_get_key( - $pa_config, - $dbh, - $task->{'auth_strings'} - ); - - # Inside an eval, here it shouln't fail unless bad configured. - $task->{'username'} = $key->{'username'}; - $task->{'password'} = $key->{'password'}; - - } - } - - my $recon = new PandoraFMS::Recon::Base( - communities => \@communities, - dbh => $dbh, - group_id => $task->{'id_group'}, - id_os => $task->{'id_os'}, - id_network_profile => $task->{'id_network_profile'}, - os_detection => $task->{'os_detect'}, - parent_detection => $task->{'parent_detection'}, - parent_recursion => $task->{'parent_recursion'}, - pa_config => $pa_config, - recon_ports => $task->{'recon_ports'}, - resolve_names => $task->{'resolve_names'}, - snmp_auth_user => $task->{'snmp_auth_user'}, - snmp_auth_pass => $task->{'snmp_auth_pass'}, - snmp_auth_method => $task->{'snmp_auth_method'}, - snmp_checks => $task->{'snmp_checks'}, - snmp_enabled => $task->{'snmp_enabled'}, - snmp_privacy_method => $task->{'snmp_privacy_method'}, - snmp_privacy_pass => $task->{'snmp_privacy_pass'}, - snmp_security_level => $task->{'snmp_security_level'}, - snmp_timeout => $task->{'snmp_timeout'}, - snmp_version => $task->{'snmp_version'}, - subnets => \@subnets, - task_id => $task->{'id_rt'}, - vlan_cache_enabled => $task->{'vlan_enabled'}, - wmi_enabled => $task->{'wmi_enabled'}, - auth_strings_array => \@auth_strings, - autoconfiguration_enabled => $task->{'autoconfiguration_enabled'}, - main_event_id => $main_event, - server_id => $server_id, - %{$pa_config}, - task_data => $task, - public_url => PandoraFMS::Config::pandora_get_tconfig_token($dbh, 'public_url', ''), - %cnf_extra - ); - - $recon->scan(); - - # Clean tmp file. - if (defined($cnf_extra{'creds_file'}) - && -f $cnf_extra{'creds_file'}) { - unlink($cnf_extra{'creds_file'}); - } - - - # Clean one shot tasks - if ($task->{'type'} eq DISCOVERY_DEPLOY_AGENTS) { - db_delete_limit($dbh, ' trecon_task ', ' id_rt = ? ', 1, $task->{'id_rt'}); - } - }; - if ($@) { - logger( - $pa_config, - 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@, - 10 - ); - update_recon_task ($dbh, $task_id, -1); - return; + my %cnf_extra; + + my $r = enterprise_hook( + 'discovery_generate_extra_cnf', + [ + $pa_config, + $dbh, $task, + \%cnf_extra + ] + ); + if (defined($r) && $r eq 'ERR') { + # Could not generate extra cnf, skip this task. + return; } + + if ($task->{'type'} == DISCOVERY_APP_SAP) { + # SAP TASK, retrieve license. + $task->{'sap_license'} = pandora_get_config_value( + $dbh, + 'sap_license' + ); + + # Retrieve credentials for task (optional). + if (defined($task->{'auth_strings'}) + && $task->{'auth_strings'} ne '' + ) { + my $key = credential_store_get_key( + $pa_config, + $dbh, + $task->{'auth_strings'} + ); + + # Inside an eval, here it shouln't fail unless bad configured. + $task->{'username'} = $key->{'username'}; + $task->{'password'} = $key->{'password'}; + + } + } + + my $recon = new PandoraFMS::Recon::Base( + communities => \@communities, + dbh => $dbh, + group_id => $task->{'id_group'}, + id_os => $task->{'id_os'}, + id_network_profile => $task->{'id_network_profile'}, + os_detection => $task->{'os_detect'}, + parent_detection => $task->{'parent_detection'}, + parent_recursion => $task->{'parent_recursion'}, + pa_config => $pa_config, + recon_ports => $task->{'recon_ports'}, + resolve_names => $task->{'resolve_names'}, + snmp_auth_user => $task->{'snmp_auth_user'}, + snmp_auth_pass => $task->{'snmp_auth_pass'}, + snmp_auth_method => $task->{'snmp_auth_method'}, + snmp_checks => $task->{'snmp_checks'}, + snmp_enabled => $task->{'snmp_enabled'}, + snmp_privacy_method => $task->{'snmp_privacy_method'}, + snmp_privacy_pass => $task->{'snmp_privacy_pass'}, + snmp_security_level => $task->{'snmp_security_level'}, + snmp_timeout => $task->{'snmp_timeout'}, + snmp_version => $task->{'snmp_version'}, + subnets => \@subnets, + task_id => $task->{'id_rt'}, + vlan_cache_enabled => $task->{'vlan_enabled'}, + wmi_enabled => $task->{'wmi_enabled'}, + auth_strings_array => \@auth_strings, + autoconfiguration_enabled => $task->{'autoconfiguration_enabled'}, + main_event_id => $main_event, + server_id => $server_id, + %{$pa_config}, + task_data => $task, + public_url => PandoraFMS::Config::pandora_get_tconfig_token($dbh, 'public_url', ''), + %cnf_extra + ); + + $recon->scan(); + + # Clean tmp file. + if (defined($cnf_extra{'creds_file'}) + && -f $cnf_extra{'creds_file'}) { + unlink($cnf_extra{'creds_file'}); + } + + + # Clean one shot tasks + if ($task->{'type'} eq DISCOVERY_DEPLOY_AGENTS) { + db_delete_limit($dbh, ' trecon_task ', ' id_rt = ? ', 1, $task->{'id_rt'}); + } + }; + if ($@) { + logger( + $pa_config, + 'Cannot execute Discovery task: ' . safe_output($task->{'name'}) . $@, + 10 + ); + update_recon_task ($dbh, $task_id, -1); + return; + } } -########################################################################## +################################################################################ # Update recon task status. -########################################################################## +################################################################################ sub update_recon_task ($$$) { - my ($dbh, $id_task, $status) = @_; - - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task); + my ($dbh, $id_task, $status) = @_; + + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ?, status = ? WHERE id_rt = ?', time (), $status, $id_task); } -########################################################################## +################################################################################ # Executes recon scripts -########################################################################## +################################################################################ sub exec_recon_script ($$$) { - my ($pa_config, $dbh, $task) = @_; - - # Get recon plugin data - my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'}); - return -1 unless defined ($script); - - logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10); - - my $command = safe_output($script->{'script'}); - - my $macros = safe_output($task->{'macros'}); + my ($pa_config, $dbh, $task) = @_; + + # Get recon plugin data + my $script = get_db_single_row ($dbh, 'SELECT * FROM trecon_script WHERE id_recon_script = ?', $task->{'id_recon_script'}); + return -1 unless defined ($script); + + logger($pa_config, 'Executing recon script ' . safe_output($script->{'name'}), 10); + + my $command = safe_output($script->{'script'}); + + my $macros = safe_output($task->{'macros'}); - # \r and \n should be escaped for decode_json(). - $macros =~ s/\n/\\n/g; - $macros =~ s/\r/\\r/g; - my $decoded_macros; - - if ($macros) { - eval { - $decoded_macros = decode_json(encode_utf8($macros)); - }; - } - - my $macros_parameters = ''; - - # Add module macros as parameter - if(ref($decoded_macros) eq "HASH") { - # Convert the hash to a sorted array - my @sorted_macros; - while (my ($i, $m) = each (%{$decoded_macros})) { - $sorted_macros[$i] = $m; - } - - # Remove the 0 position - shift @sorted_macros; - - foreach my $m (@sorted_macros) { - $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"'; - } + # \r and \n should be escaped for decode_json(). + $macros =~ s/\n/\\n/g; + $macros =~ s/\r/\\r/g; + my $decoded_macros; + + if ($macros) { + eval { + $decoded_macros = decode_json(encode_utf8($macros)); + }; + } + + my $macros_parameters = ''; + + # Add module macros as parameter + if(ref($decoded_macros) eq "HASH") { + # Convert the hash to a sorted array + my @sorted_macros; + while (my ($i, $m) = each (%{$decoded_macros})) { + $sorted_macros[$i] = $m; } - my $ent_script = 0; - my $args = enterprise_hook('discovery_custom_recon_scripts',[$pa_config, $dbh, $task, $script]); - if (!$args) { - $args = "$task->{'id_rt'} $task->{'id_group'} $task->{'create_incident'} $macros_parameters"; - } else { - $ent_script = 1; - } - - if (-x $command) { - my $exec_output = `$command $args`; - logger($pa_config, "Execution output: \n". $exec_output, 10); - } else { - logger($pa_config, "Cannot execute recon task command $command.", 10); - } - - # Only update the timestamp in case something went wrong. The script should set the status. - db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'}); + # Remove the 0 position + shift @sorted_macros; - if ($ent_script == 1) { - enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]); + foreach my $m (@sorted_macros) { + $macros_parameters = $macros_parameters . ' "' . $m->{"value"} . '"'; } - - logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10); - return 0; + } + + my $ent_script = 0; + my $args = enterprise_hook( + 'discovery_custom_recon_scripts', + [$pa_config, $dbh, $task, $script] + ); + if (!$args) { + $args = '"'.$task->{'id_rt'}.'" '; + $args .= '"'.$task->{'id_group'}.'" '; + $args .= $macros_parameters; + } else { + $ent_script = 1; + } + + if (-x $command) { + my $exec_output = `$command $args`; + logger($pa_config, "Execution output: \n". $exec_output, 10); + } else { + logger($pa_config, "Cannot execute recon task command $command.", 10); + } + + # Only update the timestamp in case something went wrong. The script should set the status. + db_do ($dbh, 'UPDATE trecon_task SET utimestamp = ? WHERE id_rt = ?', time (), $task->{'id_rt'}); + + if ($ent_script == 1) { + enterprise_hook('discovery_clean_custom_recon',[$pa_config, $dbh, $task, $script]); + } + + logger($pa_config, 'Done executing recon script ' . safe_output($script->{'name'}), 10); + return 0; } -########################################################################## +################################################################################ # Guess the OS using xprobe2 or nmap. -########################################################################## +################################################################################ sub PandoraFMS::Recon::Base::guess_os($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $DEVNULL = '/dev/null' if (!defined($DEVNULL)); - $DEVNULL = '/NUL' if ($^O =~ /win/i && !defined($DEVNULL)); + $DEVNULL = '/dev/null' if (!defined($DEVNULL)); + $DEVNULL = '/NUL' if ($^O =~ /win/i && !defined($DEVNULL)); - # OS detection disabled. Use the device type. - if ($self->{'os_detection'} == 0) { - my $device_type = $self->get_device_type($device); - return OS_OTHER unless defined($device_type); - - return OS_ROUTER if ($device_type eq 'router'); - return OS_SWITCH if ($device_type eq 'switch'); - return OS_OTHER; - } - - # Use xprobe2 if available - if (-x $self->{'pa_config'}->{'xprobe2'}) { - my $return = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL`; - if ($? == 0) { - if($return =~ /Running OS:(.*)/) { - return pandora_get_os($self->{'dbh'}, $1); - } - } - } - - # Use nmap by default - if (-x $self->{'pa_config'}->{'nmap'}) { - my $return = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL`; - return OS_OTHER if ($? != 0); - - if ($return =~ /Aggressive OS guesses:\s*(.*)/) { - return pandora_get_os($self->{'dbh'}, $1); - } - } + # OS detection disabled. Use the device type. + if ($self->{'os_detection'} == 0) { + my $device_type = $self->get_device_type($device); + return OS_OTHER unless defined($device_type); + return OS_ROUTER if ($device_type eq 'router'); + return OS_SWITCH if ($device_type eq 'switch'); return OS_OTHER; + } + + # Use xprobe2 if available + if (-x $self->{'pa_config'}->{'xprobe2'}) { + my $return = `"$self->{pa_config}->{xprobe2}" $device 2>$DEVNULL`; + if ($? == 0) { + if($return =~ /Running OS:(.*)/) { + return pandora_get_os($self->{'dbh'}, $1); + } + } + } + + # Use nmap by default + if (-x $self->{'pa_config'}->{'nmap'}) { + my $return = `"$self->{pa_config}->{nmap}" -F -O $device 2>$DEVNULL`; + return OS_OTHER if ($? != 0); + + if ($return =~ /Aggressive OS guesses:\s*(.*)/) { + return pandora_get_os($self->{'dbh'}, $1); + } + } + + return OS_OTHER; } -############################################################################## +################################################################################ # Returns the number of open ports from the given list. -############################################################################## +################################################################################ sub PandoraFMS::Recon::Base::tcp_scan ($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - my $r = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host`; + my $r = `"$self->{pa_config}->{nmap}" -p$self->{recon_ports} $host`; - # Same as ""| grep open | wc -l" but multi-OS; - my $open_ports = () = $r =~ /open/gm; + # Same as ""| grep open | wc -l" but multi-OS; + my $open_ports = () = $r =~ /open/gm; - return $open_ports; + return $open_ports; } -########################################################################## -# Create network profile modules for the given agent. -########################################################################## -sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) { - my ($self, $agent_id, $device) = @_; - - return unless ($self->{'id_network_profile'} > 0); - - # Get network components associated to the network profile. - my @np_components = get_db_rows($self->{'dbh'}, 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', $self->{'id_network_profile'}); - foreach my $np_component (@np_components) { +################################################################################ +# Verifies if a module will be normal. +################################################################################ +sub PandoraFMS::Recon::Base::test_module($$) { + my ($self, $addr, $module) = @_; - # Get network component data - my $component = get_db_single_row($self->{'dbh'}, 'SELECT * FROM tnetwork_component WHERE id_nc = ?', $np_component->{'id_nc'}); - if (!defined ($component)) { - $self->call('message', "Network component ID " . $np_component->{'id_nc'} . " not found.", 5); - next; + # Default values. + my $test = { + %{$module}, + 'ip_target' => $addr, + }; + + if (is_enabled($module->{'__module_component'})) { + # Component. Translate some fields. + $test->{'id_tipo_modulo'} = $module->{'type'}; + } else { + # Module. + $module->{'type'} = $module->{'module_type'} if is_empty($module->{'type'}); + + if (defined($module->{'type'})) { + if(!defined($self->{'module_types'}{$module->{'type'}})) { + $self->{'module_types'}{$module->{'type'}} = get_module_id( + $self->{'dbh'},$module->{'type'} + ); + } + + $test->{'id_tipo_modulo'} = $self->{'module_types'}{$module->{'type'}}; + } + } + + my $value; + + # 1. Try to retrieve value. + if ($test->{'id_tipo_modulo'} >= 15 && $test->{'id_tipo_modulo'} <= 18) { + # SNMP + $value = $self->call( + 'snmp_get_value', + $test->{'ip_target'}, + $test->{'snmp_oid'} + ); + } elsif ($test->{'id_tipo_modulo'} == 6) { + # ICMP - alive - already tested. + $value = 1; + + } elsif ($test->{'id_tipo_modulo'} == 7) { + # ICMP - latency + $value = pandora_ping_latency( + $self->{'pa_config'}, + $test->{'ip_target'}, + $test->{'max_timeout'}, + $test->{'max_retries'}, + ); + + } elsif (($test->{'id_tipo_modulo'} >= 1 && $test->{'id_tipo_modulo'} <= 5) + || ($test->{'id_tipo_modulo'} >= 21 && $test->{'id_tipo_modulo'} <= 23) + ) { + # Generic, plugins. (21-23 ASYNC) + if ($test->{'id_modulo'} == 6) { + # WMI commands. + $value = $self->call( + 'wmi_get_value', + $test->{'ip_target'}, + # WMI query. + $test->{'snmp_oid'}, + # Column + $test->{'tcp_port'} + ); + } elsif(is_enabled($test->{'id_plugin'})) { + # XXX TODO: Test plugins. How to identify arguments? and values? + # Disabled until we can ensure result. + return 0; + } + + } 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; + + } elsif ($test->{'id_tipo_modulo'} >= 8 && $test->{'id_tipo_modulo'} <= 11) { + # TCP + return 0 unless is_numeric($test->{'tcp_port'}) + && $test->{'tcp_port'} > 0 + && $test->{'tcp_port'} <= 65535; + + my $result; + + PandoraFMS::NetworkServer::pandora_query_tcp( + $self->{'pa_config'}, + $test->{'tcp_port'}, + $test->{'ip_target'}, + \$result, + \$value, + $test->{'tcp_send'}, + $test->{'tcp_rcv'}, + $test->{'id_tipo_modulo'}, + $test->{'max_timeout'}, + $test->{'max_retries'}, + '', + ); + + # Result 0 is OK, 1 failed + return 0 unless defined($result) && $result == 0; + return 0 unless defined($value); + + } + + # Invalid data (empty or not defined) + 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'} + ) + ) { + # Numeric. Remove " symbols if any. + $value =~ s/\"//g; + return 0 unless is_numeric($value); + + if (is_in_array([2,6,9,18,21,31,35], $test->{'id_tipo_modulo'})) { + # Boolean. + if (!is_enabled($test->{'critical_inverse'})) { + return 0 if $value == 0; + } else { + return 0 if $value != 0; + } + } + + 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'})) { + return 0 if !is_empty($test->{'str_critical'}) && $value =~ /$test->{'str_critical'}/; + } else { + return 0 if !is_empty($test->{'str_critical'}) && $value !~ /$test->{'str_critical'}/; + } + + } + + # Success. + return 1; + +} + +################################################################################ +# Create interface modules for the given agent (if needed). +################################################################################ +sub PandoraFMS::Recon::Base::create_interface_modules($$) { + my ($self, $device) = @_; + + # Add interfaces to the agent if it responds to SNMP. + return 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. + 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); + + # Interface status module. + $self->call( + 'add_module', + $device, + { + 'id_tipo_modulo' => 18, + 'id_modulo' => 2, + 'name' => $if_name."_ifOperStatus", + 'descripcion' => safe_input( + $if_desc + ), + 'ip_target' => $device, + 'tcp_send' => $self->{'task_data'}{'snmp_version'}, + 'custom_string_1' => $self->{'task_data'}{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'task_data'}{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'task_data'}{'snmp_security_level'}, + 'plugin_parameter' => $self->{'task_data'}{'snmp_auth_method'}, + 'plugin_user' => $self->{'task_data'}{'snmp_auth_user'}, + 'plugin_pass' => $self->{'task_data'}{'snmp_auth_pass'}, + 'snmp_community' => $community, + 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOPERSTATUS.$if_index" + } + ); + + # 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)) { + # Use HC counters. + # ifHCInOctets + $self->call( + 'add_module', + $device, + { + 'id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'name' => $if_name."_ifHCInOctets", + 'descripcion' => safe_input( + 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifInOctets.' + ), + 'ip_target' => $device, + 'tcp_send' => $self->{'task_data'}{'snmp_version'}, + 'custom_string_1' => $self->{'task_data'}{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'task_data'}{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'task_data'}{'snmp_security_level'}, + 'plugin_parameter' => $self->{'task_data'}{'snmp_auth_method'}, + 'plugin_user' => $self->{'task_data'}{'snmp_auth_user'}, + 'plugin_pass' => $self->{'task_data'}{'snmp_auth_pass'}, + 'snmp_community' => $community, + 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCINOCTECTS.$if_index" } + ); + } else { + # Use 32b counters. + # ifInOctets + $self->call( + 'add_module', + $device, + { + 'id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'name' => $if_name."_ifInOctets", + 'descripcion' => safe_input( + 'The total number of octets received on the interface, including framing characters.' + ), + 'ip_target' => $device, + 'tcp_send' => $self->{'task_data'}{'snmp_version'}, + 'custom_string_1' => $self->{'task_data'}{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'task_data'}{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'task_data'}{'snmp_security_level'}, + 'plugin_parameter' => $self->{'task_data'}{'snmp_auth_method'}, + 'plugin_user' => $self->{'task_data'}{'snmp_auth_user'}, + 'plugin_pass' => $self->{'task_data'}{'snmp_auth_pass'}, + 'snmp_community' => $community, + 'snmp_oid' => "$PandoraFMS::Recon::Base::IFINOCTECTS.$if_index" + } + ); + } - # Use snmp_community from network task instead the component snmp_community + # 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)) { + # Use HC counters. + # ifHCOutOctets + $self->call( + 'add_module', + $device, + { + 'id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'name' => $if_name."_ifHCOutOctets", + 'descripcion' => safe_input( + 'The total number of octets received on the interface, including framing characters. This object is a 64-bit version of ifOutOctets.' + ), + 'ip_target' => $device, + 'tcp_send' => $self->{'task_data'}{'snmp_version'}, + 'custom_string_1' => $self->{'task_data'}{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'task_data'}{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'task_data'}{'snmp_security_level'}, + 'plugin_parameter' => $self->{'task_data'}{'snmp_auth_method'}, + 'plugin_user' => $self->{'task_data'}{'snmp_auth_user'}, + 'plugin_pass' => $self->{'task_data'}{'snmp_auth_pass'}, + 'snmp_community' => $community, + 'snmp_oid' => "$PandoraFMS::Recon::Base::IFHCOUTOCTECTS.$if_index" + } + ); + } else { + # Use 32b counters. + # ifOutOctets + $self->call( + 'add_module', + $device, + { + 'id_tipo_modulo' => 16, + 'id_modulo' => 2, + 'name' => $if_name."_ifOutOctets", + 'descripcion' => safe_input( + 'The total number of octets received on the interface, including framing characters.' + ), + 'ip_target' => $device, + 'tcp_send' => $self->{'task_data'}{'snmp_version'}, + 'custom_string_1' => $self->{'task_data'}{'snmp_privacy_method'}, + 'custom_string_2' => $self->{'task_data'}{'snmp_privacy_pass'}, + 'custom_string_3' => $self->{'task_data'}{'snmp_security_level'}, + 'plugin_parameter' => $self->{'task_data'}{'snmp_auth_method'}, + 'plugin_user' => $self->{'task_data'}{'snmp_auth_user'}, + 'plugin_pass' => $self->{'task_data'}{'snmp_auth_pass'}, + 'snmp_community' => $community, + 'snmp_oid' => "$PandoraFMS::Recon::Base::IFOUTOCTECTS.$if_index" + } + ); + } + } + +} + +################################################################################ +# 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 $key = $self->wmi_credentials_key($target); + my $creds = $self->call('get_credentials', $key); + + # 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, + { + 'ip_target' => $target, + 'snmp_oid' => "SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId=\'$cpu\'", + 'plugin_user' => $creds->{'username'}, + 'plugin_pass' => $creds->{'password'}, + 'tcp_port' => 1, + 'name' => "CPU Load $cpu", + 'descripcion' => 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, + { + 'ip_target' => $target, + 'snmp_oid' => "SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem", + 'plugin_user' => $creds->{'username'}, + 'plugin_pass' => $creds->{'password'}, + 'tcp_port' => 0, + 'name' => 'FreeMemory', + 'descripcion' => 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, + { + 'ip_target' => $target, + 'snmp_oid' => "SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'", + 'plugin_user' => $creds->{'username'}, + 'plugin_pass' => $creds->{'password'}, + 'tcp_port' => 1, + 'name' => "FreeDisk $unit", + 'descripcion' => safe_input('Available disk space in kilobytes'), + 'id_tipo_modulo' => 1, + 'id_modulo' => 6, + 'unit' => 'KB', + } + ); + } + +} + +################################################################################ +# Create network profile modules for the given agent. +################################################################################ +sub PandoraFMS::Recon::Base::create_network_profile_modules($$) { + my ($self, $device) = @_; + + my @template_ids = (); + + if (is_enabled($self->{'task_data'}{'auto_monitor'})) { + # Apply PEN monitoring template (HW). + my @pen_templates= get_pen_templates($self->{'dbh'}, $self->get_pen($device)); + # Join. + @template_ids = (@template_ids, @pen_templates); + } else { + # Return if no specific templates are selected. + return if is_empty($self->{'id_network_profile'}); + } + + push @template_ids, split /,/, $self->{'id_network_profile'} + unless is_empty($self->{'id_network_profile'}); + + my $data = $self->{'agents_found'}{$device}; + + foreach my $t_id (@template_ids) { + # 1. Retrieve template info. + my $template = get_nc_profile_advanced($self->{'dbh'}, $t_id); + + # 2. Verify Private Enterprise Number matches (PEN) + if (defined($template->{'pen'})) { + my @penes = split(',', $template->{'pen'}); + + next unless (is_in_array(\@penes, $self->get_pen($device))); + } + + # 3. Retrieve module list from target template. + my @np_components = get_db_rows( + $self->{'dbh'}, + 'SELECT * FROM tnetwork_profile_component WHERE id_np = ?', + $t_id + ); + + foreach my $np_component (@np_components) { + # 4. Register each module (candidate). 'add_module' will test them. + my $component = get_db_single_row( + $self->{'dbh'}, + 'SELECT * FROM tnetwork_component WHERE id_nc = ?', + $np_component->{'id_nc'} + ); + + $component->{'name'} = safe_output($component->{'name'}); + if ($component->{'type'} >= 15 && $component->{'type'} <= 18) { $component->{'snmp_community'} = safe_output($self->get_community($device)); $component->{'tcp_send'} = $self->{'snmp_version'}; $component->{'custom_string_1'} = $self->{'snmp_privacy_method'}; @@ -464,566 +915,726 @@ sub PandoraFMS::Recon::Base::create_network_profile_modules($$$) { $component->{'plugin_parameter'} = $self->{'snmp_auth_method'}; $component->{'plugin_user'} = $self->{'snmp_auth_user'}; $component->{'plugin_pass'} = $self->{'snmp_auth_pass'}; + } - pandora_create_module_from_network_component($self->{'pa_config'}, $component, $agent_id, $self->{'dbh'}); + $component->{'__module_component'} = 1; + + # 3. Try to register module into monitoring list. + $self->call('add_module', $device, $component); } + } + } -########################################################################## +################################################################################ +# 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. +################################################################################ +sub PandoraFMS::Recon::Base::report_scanned_agents($;$) { + my ($self,$force) = @_; + + my $force_creation = $force; + $force_creation = 0 unless (is_enabled($force)); + + # + # Creation + # + + if($force_creation == 1 + || (defined($self->{'task_data'}{'review_mode'}) + && $self->{'task_data'}{'review_mode'} == DISCOVERY_RESULTS) + ) { + + # Load cache. + my @rows = get_db_rows( + $self->{'dbh'}, + 'SELECT * FROM tdiscovery_tmp_agents WHERE `id_rt`=?', + $self->{'task_data'}{'id_rt'} + ); + + # Return if no entries. + return unless scalar @rows > 0; + + my @agents; + + my $progress = 0; + my $step = 100.00 / scalar @rows; + foreach my $row (@rows) { + $progress += $step; + $self->call('update_progress', $progress); + + my $name = safe_output($row->{'label'}); + my $checked = 0; + my $data; + eval { + local $SIG{__DIE__}; + $data = decode_json(decode_base64($row->{'data'})); + }; + if ($@) { + $self->call('message', "ERROR JSON: $@", 3); + } + + # Agent could be 'not checked' unless all modules are selected. + if (ref($data->{'modules'}) eq 'HASH') { + my @map = map { + my $name = $_->{'name'}; + $name = $_->{'nombre'} if is_empty($name); + + if (is_enabled($_->{'checked'}) + && $name ne 'Host Alive' + ) { + $name; + } else {} + + } values %{$data->{'modules'}}; + + $checked = scalar @map; + } + + $checked = $data->{'agent'}{'checked'} if + is_enabled($data->{'agent'}{'checked'}) + && $checked < $data->{'agent'}{'checked'}; + + # Register target agent if enabled. + if (is_enabled($checked) + || $force_creation + ) { + my $parent_id; + my $os_id = $self->guess_os($data->{'agent'}{'direccion'}); + + $self->call('message', "Agent accepted: ".$data->{'agent'}{'nombre'}, 5); + + # Agent creation. + my $agent_id = $data->{'agent'}{'agent_id'}; + my $agent_learning; + + if (defined($agent_id) && $agent_id > 0) { + $agent_learning = get_db_value( + $self->{'dbh'}, + 'SELECT modo FROM tagente WHERE id_agente = ?', + $agent_id + ); + } + + 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'}) + ); + + if (!defined($agent_id) || $agent_id <= 0) { + # 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'} + ); + + # Agent autoconfiguration. + if (is_enabled($self->{'autoconfiguration_enabled'})) { + 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'}, + $data->{'agent'}{'direccion'}, + $agent_id, + $agent_data, + $self->{'dbh'}, + 1 + ] + ); + } + + if (defined($self->{'main_event_id'})) { + my $addresses_str = join( + ',', + $self->get_addresses(safe_output($data->{'agent'}{'nombre'})) + ); + + pandora_extended_event( + $self->{'pa_config'}, $self->{'dbh'}, + $self->{'main_event_id'},"[Discovery] New " + . $self->get_device_type(safe_output($data->{'agent'}{'nombre'})) + . " found " . $data->{'agent'}{'nombre'} . " (" . $addresses_str + . ") Agent $agent_id." + ); + } + + $agent_learning = 1; + } else { + # Read from effective agent_id. + $agent_learning = get_db_value( + $self->{'dbh'}, + 'SELECT modo FROM tagente WHERE id_agente = ?', + $agent_id + ); + } + + $data->{'agent'}{'agent_id'} = $agent_id; + } + + $data->{'agent'}{'modo'} = $agent_learning; + $self->call('message', "Agent id: ".$data->{'agent'}{'agent_id'}, 5); + + # Create selected modules. + if(ref($data->{'modules'}) eq "HASH") { + foreach my $i (keys %{$data->{'modules'}}) { + my $module = $data->{'modules'}{$i}; + + $module->{'name'} = $module->{'nombre'} if is_empty($module->{'name'}); + + # Do not create any modules if the agent is not in learning mode. + next unless ($agent_learning == 1); + + # Host alive is always being created. + if ($module->{'name'} ne 'Host Alive') { + next unless (is_enabled($module->{'checked'}) || $force_creation); + } + + $self->call('message', "[$agent_id] Module: ".$module->{'name'}, 5); + + my $agentmodule_id = get_db_value( + $self->{'dbh'}, + 'SELECT id_agente_modulo FROM tagente_modulo + WHERE id_agente = ? AND nombre = ?', + $agent_id, + safe_input($module->{'name'}) + ); + + if (!is_enabled($agentmodule_id)) { + # Create. + + # Delete unwanted fields. + delete $module->{'agentmodule_id'}; + delete $module->{'checked'}; + + my $id_tipo_modulo = $module->{'id_tipo_modulo'}; + $id_tipo_modulo = get_module_id($self->{'dbh'}, $module->{'type'}) + if is_empty($id_tipo_modulo); + + my $description = safe_output($module->{'description'}); + $description = '' if is_empty($description); + + if (is_enabled($module->{'__module_component'})) { + # Module from network component. + delete $module->{'__module_component'}; + $agentmodule_id = pandora_create_module_from_network_component( + $self->{'pa_config'}, + # Send a copy, not original, because of 'deletes' + { + %{$module}, + 'name' => safe_input($module->{'name'}), + }, + $agent_id, + $self->{'dbh'} + ); + + # Restore. + $module->{'__module_component'} = 1; + } else { + # Create module - Direct. + my $name = $module->{'name'}; + delete $module->{'name'}; + delete $module->{'description'}; + $agentmodule_id = pandora_create_module_from_hash( + $self->{'pa_config'}, + { + %{$module}, + 'id_tipo_modulo' => $id_tipo_modulo, + 'id_modulo' => $module->{'id_modulo'}, + 'nombre' => safe_input($name), + 'descripcion' => safe_input($description), + 'id_agente' => $agent_id, + 'ip_target' => $data->{'agent'}{'direccion'} + }, + $self->{'dbh'} + ); + + $module->{'name'} = $name; + $module->{'description'} = safe_output($description); + } + + # Restore. + $module->{'checked'} = 1; + + # Store. + $data->{'modules'}{$i}{'agentmodule_id'} = $agentmodule_id; + + $self->call( + 'message', + "[$agent_id] Module: ".$module->{'name'}." ID: $agentmodule_id", + 5 + ); + } + } + } + + my $encoded; + eval { + local $SIG{__DIE__}; + $encoded = encode_base64( + encode_json($data) + ); + }; + + push @agents, $data->{'agent'}; + + # Update. + db_do( + $self->{'dbh'}, + 'UPDATE tdiscovery_tmp_agents SET `data` = ? ' + .'WHERE `id_rt` = ? AND `label` = ?', + $encoded, + $self->{'task_data'}{'id_rt'}, + $name + ); + + } + + } + + # Update parent relationships. + foreach my $agent (@agents) { + + # Avoid processing if does not exist. + next unless (defined($agent->{'agent_id'})); + + # Avoid processing undefined parents. + 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'}); + } + next unless defined($parent); + + # Is the agent in learning mode? + next unless ($agent->{'modo'} == 1); + + # Connect the host to its parent. + db_do($self->{'dbh'}, + 'UPDATE tagente SET id_parent=? WHERE id_agente=?', + $parent->{'id_agente'}, $agent->{'agent_id'} + ); + } + + # Connect agents. + my @connections = get_db_rows( + $self->{'dbh'}, + 'SELECT * FROM tdiscovery_tmp_connections WHERE id_rt = ?', + $self->{'task_data'}{'id_rt'} + ); + + foreach my $cn (@connections) { + $self->call('connect_agents', + $cn->{'dev_1'}, + $cn->{'if_1'}, + $cn->{'dev_2'}, + $cn->{'if_2'}, + # Force creation if direct. + $force_creation + ); + } + + # Data creation finished. + return; + } + + + # + # Cleanup previous results. + # + $self->call('message', "Cleanup previous results", 6); + db_do( + $self->{'dbh'}, + 'DELETE FROM tdiscovery_tmp_agents ' + .'WHERE `id_rt` = ?', + $self->{'task_data'}{'id_rt'} + ); + + # + # Store and review. + # + + $self->call('message', "Storing results", 6); + 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'}}) { + $self->call('update_progress', $progress); + $progress += $step; + # Store temporally. Wait user approval. + my $encoded; + eval { + local $SIG{__DIE__}; + $encoded = encode_base64( + encode_json($self->{'agents_found'}->{$label}) + ); + }; + + my $id = get_db_value( + $self->{'dbh'}, + 'SELECT id FROM tdiscovery_tmp_agents WHERE id_rt = ? AND label = ?', + $self->{'task_data'}{'id_rt'}, + safe_input($label) + ); + + if (defined($id)) { + # Already defined. + $self->{'agents_found'}{$label}{'id'} = $id; + + db_do( + $self->{'dbh'}, + 'UPDATE tdiscovery_tmp_agents SET `data` = ? ' + .'WHERE `id_rt` = ? AND `label` = ?', + $encoded, + $self->{'task_data'}{'id_rt'}, + safe_input($label) + ); + next; + } + + # Insert. + $self->{'agents_found'}{$label}{'id'} = db_insert( + $self->{'dbh'}, + 'id', + 'INSERT INTO tdiscovery_tmp_agents (`id_rt`,`label`,`data`,`created`) ' + .'VALUES (?, ?, ?, now())', + $self->{'task_data'}{'id_rt'}, + safe_input($label), + $encoded + ); + } + + + if(defined($self->{'task_data'}{'review_mode'}) + && $self->{'task_data'}{'review_mode'} == DISCOVERY_REVIEW + ) { + # Notify. + my $notification = {}; + $notification->{'subject'} = safe_input('Discovery task '); + $notification->{'subject'} .= $self->{'task_data'}{'name'}; + $notification->{'subject'} .= safe_input(' review pending'); + $notification->{'url'} = ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=tasklist#' + ); + + $notification->{'mensaje'} = safe_input( + 'Discovery task (host&devices) \''.safe_output($self->{'task_data'}{'name'}) + .'\' has been completed. Please review the results.' + ); + + $notification->{'id_source'} = get_db_value( + $self->{'dbh'}, + 'SELECT id FROM tnotification_source WHERE description = ?', + safe_input('System status') + ); + + # Create message + my $notification_id = db_process_insert( + $self->{'dbh'}, + 'id_mensaje', + 'tmensajes', + $notification + ); + + if (is_enabled($notification_id)) { + my @users = notification_get_users($self->{'dbh'}, 'System status'); + my @groups = notification_get_groups($self->{'dbh'}, 'System status'); + + notification_set_targets( + $self->{'pa_config'}, $self->{'dbh'}, + $notification_id, \@users, \@groups + ); + } + } + + $self->call('message', "Completed", 5); +} + +################################################################################ +# Apply monitoring templates selected to detected agents. +################################################################################ +sub PandoraFMS::Recon::Base::apply_monitoring($) { + my ($self) = @_; + + my @hosts = keys %{$self->{'agents_found'}}; + + $self->{'step'} = STEP_MONITORING; + # From 80% to 90%. + my ($progress, $step) = (80, 10.0 / scalar(@hosts)); + my ($partial, $sub_step) = (0, 100 / scalar(@hosts)); + + foreach my $label (keys %{$self->{'agents_found'}}) { + $self->{'c_network_percent'} = $partial; + $self->{'c_network_name'} = $label; + $self->call('update_progress', $progress); + $progress += $step; + $partial += $sub_step; + $self->call('message', "Checking modules for $label", 5); + + # Monitorization selected. + $self->call('create_network_profile_modules', $label); + + # Monitorization - interfaces + $self->call('create_interface_modules', $label); + + # Monitorization - WMI modules. + $self->call('create_wmi_modules', $label); + + } + + $self->{'c_network_percent'} = 100; + $self->call('update_progress', $progress); +} + +################################################################################ # Connect the given devices in the Pandora FMS database. -########################################################################## -sub PandoraFMS::Recon::Base::connect_agents($$$$$) { - my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; +################################################################################ +sub PandoraFMS::Recon::Base::connect_agents($$$$$;$) { + my ($self, $dev_1, $if_1, $dev_2, $if_2, $force) = @_; - # Get the agent for the first device. - my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1); - if (!defined($agent_1)) { - $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1); - } - return unless defined($agent_1); + if($self->{'task_data'}{'review_mode'} == DISCOVERY_REVIEW + || is_enabled($force) + ) { + # Store in tdiscovery_tmp_connections; - # Get the agent for the second device. - my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2); - if (!defined($agent_2)) { - $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2); - } - return unless defined($agent_2); + db_process_insert( + $self->{'dbh'}, + 'id', + 'tdiscovery_tmp_connections', + { + 'id_rt' => $self->{'task_data'}{'id_rt'}, + 'dev_1' => $dev_1, + 'if_1' => $if_1, + 'dev_2' => $dev_2, + 'if_2' => $if_2, + } + ); - # Use ping modules by default. - $if_1 = 'ping' if ($if_1 eq ''); - $if_2 = 'ping' if ($if_2 eq ''); + return; + } - # Check whether the modules exists. - my $module_name_1 = $if_1 eq 'ping' ? 'ping' : "${if_1}_ifOperStatus"; - my $module_name_2 = $if_2 eq 'ping' ? 'ping' : "${if_2}_ifOperStatus"; - my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'}); - if ($module_id_1 <= 0) { - $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5); - return; - } - my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'}); - if ($module_id_2 <= 0) { - $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5); - return; - } + # Get the agent for the first device. + my $agent_1 = get_agent_from_addr($self->{'dbh'}, $dev_1); + if (!defined($agent_1)) { + $agent_1 = get_agent_from_name($self->{'dbh'}, $dev_1); + } + return unless defined($agent_1); - # Connect the modules if they are not already connected. - my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ? AND `type` = "direct") OR (module_b = ? AND module_a = ? AND `type` = "direct")', $module_id_1, $module_id_2, $module_id_1, $module_id_2); - if (! defined($connection_id)) { - db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'}); - } + # Get the agent for the second device. + my $agent_2 = get_agent_from_addr($self->{'dbh'}, $dev_2); + if (!defined($agent_2)) { + $agent_2 = get_agent_from_name($self->{'dbh'}, $dev_2); + } + return unless defined($agent_2); + + # Use ping modules by default. + $if_1 = 'Host Alive' if ($if_1 eq ''); + $if_2 = 'Host Alive' if ($if_2 eq ''); + + # Check whether the modules exists. + my $module_name_1 = $if_1 eq 'Host Alive' ? 'Host Alive' : "${if_1}_ifOperStatus"; + my $module_name_2 = $if_2 eq 'Host Alive' ? 'Host Alive' : "${if_2}_ifOperStatus"; + my $module_id_1 = get_agent_module_id($self->{'dbh'}, $module_name_1, $agent_1->{'id_agente'}); + if ($module_id_1 <= 0) { + $self->call('message', "ERROR: Module " . safe_output($module_name_1) . " does not exist for agent $dev_1.", 5); + return; + } + my $module_id_2 = get_agent_module_id($self->{'dbh'}, $module_name_2, $agent_2->{'id_agente'}); + if ($module_id_2 <= 0) { + $self->call('message', "ERROR: Module " . safe_output($module_name_2) . " does not exist for agent $dev_2.", 5); + return; + } + + # Connect the modules if they are not already connected. + my $connection_id = get_db_value($self->{'dbh'}, 'SELECT id FROM tmodule_relationship WHERE (module_a = ? AND module_b = ? AND `type` = "direct") OR (module_b = ? AND module_a = ? AND `type` = "direct")', $module_id_1, $module_id_2, $module_id_1, $module_id_2); + if (! defined($connection_id)) { + db_do($self->{'dbh'}, 'INSERT INTO tmodule_relationship (`module_a`, `module_b`, `id_rt`) VALUES(?, ?, ?)', $module_id_1, $module_id_2, $self->{'task_id'}); + } } -########################################################################## +################################################################################ # Create agents from db_scan. Uses DataServer methods. # data = [ # 'agent_data' => {}, # 'module_data' => [] # ] -########################################################################## +################################################################################ sub PandoraFMS::Recon::Base::create_agents($$) { - my ($self, $data) = @_; + my ($self, $data) = @_; - my $pa_config = $self->{'pa_config'}; - my $dbh = $self->{'dbh'}; - my $server_id = $self->{'server_id'}; + my $pa_config = $self->{'pa_config'}; + my $dbh = $self->{'dbh'}; + my $server_id = $self->{'server_id'}; - return undef if (ref($data) ne "ARRAY"); + return undef if (ref($data) ne "ARRAY"); - foreach my $information (@{$data}) { - my $agent = $information->{'agent_data'}; - my $modules = $information->{'module_data'}; - my $force_processing = 0; + foreach my $information (@{$data}) { + my $agent = $information->{'agent_data'}; + my $modules = $information->{'module_data'}; + my $force_processing = 0; - # Search agent - my $current_agent = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'agent_name'} - ); - - my $parent_id; - if (defined($agent->{'parent_agent_name'})) { - $parent_id = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'parent_agent_name'} - ); - if ($parent_id) { - $parent_id = $parent_id->{'id_agente'}; - } - } - - my $agent_id; - my $os_id = get_os_id($dbh, $agent->{'os'}); - - if ($os_id < 0) { - $os_id = get_os_id($dbh, 'Other'); - } - - if (!$current_agent) { - # Create agent. - $agent_id = pandora_create_agent( - $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'}, - $agent->{'address'}, $agent->{'id_group'}, $parent_id, - $os_id, $agent->{'description'}, - $agent->{'interval'}, $dbh, $agent->{'timezone_offset'} - ); - - $current_agent = $parent_id = PandoraFMS::Core::locate_agent( - $pa_config, $dbh, $agent->{'agent_name'} - ); - - $force_processing = 1; - - } else { - $agent_id = $current_agent->{'id_agente'}; - } - - if (!defined($agent_id)) { - return undef; - } - - if (defined($agent->{'address'}) && $agent->{'address'} ne '') { - pandora_add_agent_address( - $pa_config, $agent_id, $agent->{'agent_name'}, - $agent->{'address'}, $dbh - ); - } - - # Update agent information - pandora_update_agent( - $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id, - $agent->{'os_version'}, $agent->{'agent_version'}, - $agent->{'interval'}, $dbh, undef, $parent_id - ); - - # Add modules. - if (ref($modules) eq "ARRAY") { - foreach my $module (@{$modules}) { - next unless ref($module) eq 'HASH'; - # Translate data structure to simulate XML parser return. - my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module}; - - # Process modules. - PandoraFMS::DataServer::process_module_data ( - $pa_config, \%data_translated, - $server_id, $current_agent, - $module->{'name'}, $module->{'type'}, - $agent->{'interval'}, - strftime ("%Y/%m/%d %H:%M:%S", localtime()), - $dbh, $force_processing - ); - } - } - } - -} - - -########################################################################## -# 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 ($self->{'all_ifaces'} == 0) { - 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. -########################################################################## -sub PandoraFMS::Recon::Base::delete_connections($) { - my ($self) = @_; - - $self->call('message', "Deleting connections...", 10); - db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'}); -} - -####################################################################### -# Print log messages. -####################################################################### -sub PandoraFMS::Recon::Base::message($$$) { - my ($self, $message, $verbosity) = @_; - - logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity); -} - -########################################################################## -# Connect the given hosts to its parent. -########################################################################## -sub PandoraFMS::Recon::Base::set_parent($$$) { - my ($self, $host, $parent) = @_; - - return unless ($self->{'parent_detection'} == 1); - - # Get the agent for the host. - my $agent = get_agent_from_addr($self->{'dbh'}, $host); - if (!defined($agent)) { - $agent = get_agent_from_name($self->{'dbh'}, $host); - } - return unless defined($agent); - - # Check if the parent agent exists. - my $agent_parent = get_agent_from_addr($self->{'dbh'}, $parent); - if (!defined($agent_parent)) { - $agent_parent = get_agent_from_name($self->{'dbh'}, $parent); - } - return unless (defined ($agent_parent)); - - # Is the agent in learning mode? - return unless ($agent_parent->{'modo'} == 1); - - # Connect the host to its parent. - db_do($self->{'dbh'}, 'UPDATE tagente SET id_parent=? WHERE id_agente=?', $agent_parent->{'id_agente'}, $agent->{'id_agente'}); -} - -########################################################################## -# Create a WMI module for the given agent. -########################################################################## -sub PandoraFMS::Recon::Base::wmi_module { - my ($self, $agent_id, $target, $wmi_query, $wmi_auth, $column, - $module_name, $module_description, $module_type, $unit) = @_; - - # Check whether the module already exists. - my $module_id = get_agent_module_id($self->{'dbh'}, $module_name, $agent_id); - return if ($module_id > 0); - - my ($user, $pass) = ($wmi_auth ne '') ? split('%', $wmi_auth) : (undef, undef); - my %module = ( - 'descripcion' => safe_input($module_description), - 'id_agente' => $agent_id, - 'id_modulo' => 6, - 'id_tipo_modulo' => get_module_id($self->{'dbh'}, $module_type), - 'ip_target' => $target, - 'nombre' => safe_input($module_name), - 'plugin_pass' => defined($pass) ? $pass : '', - 'plugin_user' => defined($user) ? $user : '', - 'snmp_oid' => $wmi_query, - 'tcp_port' => $column, - 'unit' => defined($unit) ? $unit : '' + # Search agent + my $current_agent = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'agent_name'} ); - - pandora_create_module_from_hash($self->{'pa_config'}, \%module, $self->{'dbh'}); + + my $parent_id; + if (defined($agent->{'parent_agent_name'})) { + $parent_id = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'parent_agent_name'} + ); + if ($parent_id) { + $parent_id = $parent_id->{'id_agente'}; + } + } + + my $agent_id; + my $os_id = get_os_id($dbh, $agent->{'os'}); + + if ($os_id < 0) { + $os_id = get_os_id($dbh, 'Other'); + } + + if (!$current_agent) { + # Create agent. + $agent_id = pandora_create_agent( + $pa_config, $pa_config->{'servername'}, $agent->{'agent_name'}, + $agent->{'address'}, $agent->{'id_group'}, $parent_id, + $os_id, $agent->{'description'}, + $agent->{'interval'}, $dbh, $agent->{'timezone_offset'} + ); + + $current_agent = $parent_id = PandoraFMS::Core::locate_agent( + $pa_config, $dbh, $agent->{'agent_name'} + ); + + $force_processing = 1; + + } else { + $agent_id = $current_agent->{'id_agente'}; + } + + if (!defined($agent_id)) { + return undef; + } + + if (defined($agent->{'address'}) && $agent->{'address'} ne '') { + pandora_add_agent_address( + $pa_config, $agent_id, $agent->{'agent_name'}, + $agent->{'address'}, $dbh + ); + } + + # Update agent information + pandora_update_agent( + $pa_config, strftime("%Y-%m-%d %H:%M:%S", localtime()), $agent_id, + $agent->{'os_version'}, $agent->{'agent_version'}, + $agent->{'interval'}, $dbh, undef, $parent_id + ); + + # Add modules. + if (ref($modules) eq "ARRAY") { + foreach my $module (@{$modules}) { + next unless ref($module) eq 'HASH'; + # Translate data structure to simulate XML parser return. + my %data_translated = map { $_ => [ $module->{$_} ] } keys %{$module}; + + # Process modules. + PandoraFMS::DataServer::process_module_data ( + $pa_config, \%data_translated, + $server_id, $current_agent, + $module->{'name'}, $module->{'type'}, + $agent->{'interval'}, + strftime ("%Y/%m/%d %H:%M:%S", localtime()), + $dbh, $force_processing + ); + } + } + } + } -########################################################################## +################################################################################ +# Delete already existing connections. +################################################################################ +sub PandoraFMS::Recon::Base::delete_connections($) { + my ($self) = @_; + + $self->call('message', "Deleting connections...", 10); + db_do($self->{'dbh'}, 'DELETE FROM tmodule_relationship WHERE id_rt=?', $self->{'task_id'}); +} + +################################################################################ +# Print log messages. +################################################################################ +sub PandoraFMS::Recon::Base::message($$$) { + my ($self, $message, $verbosity) = @_; + + logger($self->{'pa_config'}, "[Recon task " . $self->{'task_id'} . "] $message", $verbosity); +} + +################################################################################ +# Connect the given hosts to its parent. +################################################################################ +sub PandoraFMS::Recon::Base::set_parent($$$) { + my ($self, $host, $parent) = @_; + + return unless ($self->{'parent_detection'} == 1); + + # Do not edit 'not scaned' agents. + return if is_empty($self->{'agents_found'}{$host}{'agent'}); + + $self->{'agents_found'}{$host}{'agent'}{'parent'} = $parent; + +} + +################################################################################ # Update recon task status. -########################################################################## +################################################################################ sub PandoraFMS::Recon::Base::update_progress ($$) { - my ($self, $progress) = @_; + my ($self, $progress) = @_; - my $stats = {}; - if (defined($self->{'summary'}) && $self->{'summary'} ne '') { - $stats->{'summary'} = $self->{'summary'}; - } - $stats->{'step'} = $self->{'step'}; - $stats->{'c_network_name'} = $self->{'c_network_name'}; - $stats->{'c_network_percent'} = $self->{'c_network_percent'}; + my $stats = {}; + if (defined($self->{'summary'}) && $self->{'summary'} ne '') { + $stats->{'summary'} = $self->{'summary'}; + } - # Store progress, last contact and overall status. - db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?', - time (), $progress, encode_json($stats), $self->{'task_id'}); + $stats->{'step'} = $self->{'step'}; + $stats->{'c_network_name'} = $self->{'c_network_name'}; + $stats->{'c_network_percent'} = $self->{'c_network_percent'}; + + # Store progress, last contact and overall status. + db_do ($self->{'dbh'}, 'UPDATE trecon_task SET utimestamp = ?, status = ?, summary = ? WHERE id_rt = ?', + time (), $progress, encode_json($stats), $self->{'task_id'}); } 1; diff --git a/pandora_server/lib/PandoraFMS/NetworkServer.pm b/pandora_server/lib/PandoraFMS/NetworkServer.pm index 216a7ae4d1..0bca799815 100644 --- a/pandora_server/lib/PandoraFMS/NetworkServer.pm +++ b/pandora_server/lib/PandoraFMS/NetworkServer.pm @@ -384,6 +384,7 @@ sub pandora_query_snmp ($$$$) { my $output; # Command output # If not defined, always snmp v1 (standard) + $snmp_version = '1' unless defined($snmp_version); if ($snmp_version ne '1' && $snmp_version ne '2' && $snmp_version ne '2c' && $snmp_version ne '3') { $snmp_version = '1'; @@ -470,7 +471,9 @@ sub exec_network_module ($$$$) { my $retries = $module->{'max_retries'}; my $target_os = pandora_get_os($dbh, $module->{'custom_string_2'}); - if ($module->{'custom_string_2'} eq "inherited" ) { + if (defined($module->{'custom_string_2'}) + && $module->{'custom_string_2'} eq "inherited" + ) { $target_os = $agent_row->{'id_os'}; } elsif (!defined($target_os) || "$target_os" eq '0') { $target_os = $agent_row->{'id_os'}; @@ -589,7 +592,7 @@ sub exec_network_module ($$$$) { my %data = ("data" => $module_data); pandora_process_module ($pa_config, \%data, '', $module, '', $timestamp, $utimestamp, $server_id, $dbh); - if ($agent_os_version eq ''){ + if (!defined($agent_os_version) || $agent_os_version eq ''){ $agent_os_version = $pa_config->{'servername'}.'_Net'; } diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 662ac96f09..fb688f9c61 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 = "200413"; +my $pandora_build = "200414"; 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 ce6048a6f9..01f8e824b8 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Base.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Base.pm @@ -7,34 +7,45 @@ use strict; use warnings; # Default lib dir for RPM and DEB packages -use lib '/usr/lib/perl5'; - use NetAddr::IP; use POSIX qw/ceil/; +use Socket qw/inet_aton/; + +use lib '/usr/lib/perl5'; +use PandoraFMS::Tools; use PandoraFMS::Recon::NmapParser; use PandoraFMS::Recon::Util; -use Socket qw/inet_aton/; # Constants. use constant { - STEP_SCANNING => 1, - STEP_AFT => 2, - STEP_TRACEROUTE => 3, - STEP_GATEWAY => 4, - STEP_STATISTICS => 1, - STEP_APP_SCAN => 2, - STEP_CUSTOM_QUERIES => 3, - DISCOVERY_HOSTDEVICES => 0, - DISCOVERY_HOSTDEVICES_CUSTOM => 1, - DISCOVERY_CLOUD_AWS => 2, - DISCOVERY_APP_VMWARE => 3, - DISCOVERY_APP_MYSQL => 4, - DISCOVERY_APP_ORACLE => 5, - DISCOVERY_CLOUD_AWS_EC2 => 6, - DISCOVERY_CLOUD_AWS_RDS => 7, - DISCOVERY_CLOUD_AZURE_COMPUTE => 8, - DISCOVERY_DEPLOY_AGENTS => 9, - DISCOVERY_APP_SAP => 10, + STEP_SCANNING => 1, + STEP_CAPABILITIES => 7, + STEP_AFT => 2, + STEP_TRACEROUTE => 3, + STEP_GATEWAY => 4, + STEP_MONITORING => 5, + STEP_PROCESSING => 6, + STEP_STATISTICS => 1, + STEP_APP_SCAN => 2, + STEP_CUSTOM_QUERIES => 3, + DISCOVERY_HOSTDEVICES => 0, + DISCOVERY_HOSTDEVICES_CUSTOM => 1, + DISCOVERY_CLOUD_AWS => 2, + DISCOVERY_APP_VMWARE => 3, + DISCOVERY_APP_MYSQL => 4, + DISCOVERY_APP_ORACLE => 5, + DISCOVERY_CLOUD_AWS_EC2 => 6, + DISCOVERY_CLOUD_AWS_RDS => 7, + DISCOVERY_CLOUD_AZURE_COMPUTE => 8, + DISCOVERY_DEPLOY_AGENTS => 9, + DISCOVERY_APP_SAP => 10, + DISCOVERY_REVIEW => 0, + DISCOVERY_STANDARD => 1, + DISCOVERY_RESULTS => 2, + WMI_UNREACHABLE => 1, + WMI_BAD_PASSWORD => 2, + WMI_GENERIC_ERROR => 3, + WMI_OK => 0, }; # $DEVNULL @@ -67,6 +78,7 @@ our $SYSDESCR = ".1.3.6.1.2.1.1.1"; our $SYSSERVICES = ".1.3.6.1.2.1.1.7"; our $SYSUPTIME = ".1.3.6.1.2.1.1.3"; our $VTPVLANIFINDEX = ".1.3.6.1.4.1.9.9.46.1.3.1.1.18.1"; +our $PEN_OID = ".1.3.6.1.2.1.1.2.0"; our @ISA = ("Exporter"); our %EXPORT_TAGS = ( 'all' => [qw( )] ); @@ -98,2060 +110,2272 @@ our @EXPORT = qw( $SYSUPTIME ); -####################################################################### +################################################################################ # Create a new ReconTask object. -####################################################################### +################################################################################ sub new { - my $class = shift; + my $class = shift; - my $self = { + my $self = { - # Known aliases (multiple IP addresses for the same host. - aliases => {}, + # Known aliases (multiple IP addresses for the same host. + aliases => {}, - # Keep our own ARP cache to connect hosts to switches/routers. - arp_cache => {}, + # Keep our own ARP cache to connect hosts to switches/routers. + arp_cache => {}, - # Found children. - children => {}, + # Found children. + children => {}, - # Working SNMP community for each device. - community_cache => {}, + # Working SNMP community for each device. + community_cache => {}, - # Cache of deviced discovered. - dicovered_cache => {}, + # Cache of deviced discovered. + dicovered_cache => {}, - # Connections between devices. - connections => {}, + # Connections between devices. + connections => {}, - # Devices by type. - hosts => [], - routers => [], - switches => [], + # Devices by type. + hosts => [], + routers => [], + switches => [], - # Found interfaces. - ifaces => {}, + # Found interfaces. + ifaces => {}, - # Found parents. - parents => {}, + # Found parents. + parents => {}, - # Route cache. - routes => [], - default_gw => undef, + # Route cache. + routes => [], + default_gw => undef, - # SNMP query cache. - snmp_cache => {}, + # SNMP query cache. + snmp_cache => {}, - # Globally enable/disable SNMP scans. - snmp_enabled => 1, + # Globally enable/disable SNMP scans. + snmp_enabled => 1, - # Globally enable/disable WMI scans. - wmi_enabled => 0, - auth_strings_array => [], - wmi_timeout => 3, - timeout_cmd => '', + # Globally enable/disable WMI scans. + wmi_enabled => 0, + auth_strings_array => [], + wmi_timeout => 3, + timeout_cmd => '', - # Switch to switch connections. Used to properly connect hosts - # that are connected to a switch wich is in turn connected to another switch, - # since the hosts will show up in the latter's switch AFT too. - switch_to_switch => {}, + # Switch to switch connections. Used to properly connect hosts + # that are connected to a switch wich is in turn connected to another switch, + # since the hosts will show up in the latter's switch AFT too. + switch_to_switch => {}, - # Visited devices (initially empty). - visited_devices => {}, + # Visited devices (initially empty). + visited_devices => {}, - # Per device VLAN cache. - vlan_cache => {}, - vlan_cache_enabled => 1, # User configuration. Globally disables the VLAN cache. - __vlan_cache_enabled__ => 0, # Internal state. Allows us to enable/disable the VLAN cache on a per SNMP query basis. + # Per device VLAN cache. + vlan_cache => {}, + vlan_cache_enabled => 1, # User configuration. Globally disables the VLAN cache. + __vlan_cache_enabled__ => 0, # Internal state. Allows us to enable/disable the VLAN cache on a per SNMP query basis. - # Configuration parameters. - all_ifaces => 0, - communities => [], - icmp_checks => 2, - icmp_timeout => 2, - id_os => 0, - id_network_profile => 0, - nmap => '/usr/bin/nmap', - parent_detection => 1, - parent_recursion => 5, - os_detection => 0, - recon_timing_template => 3, - recon_ports => '', - resolve_names => 0, - snmp_auth_user => '', - snmp_auth_pass => '', - snmp_auth_method => '', - snmp_checks => 2, - snmp_privacy_method => '', - snmp_privacy_pass => '', - snmp_security_level => '', - snmp_timeout => 2, - snmp_version => 1, - subnets => [], - autoconfiguration_enabled => 0, + # Configuration parameters. + all_ifaces => 0, + communities => [], + icmp_checks => 2, + icmp_timeout => 2, + id_os => 0, + id_network_profile => 0, + nmap => '/usr/bin/nmap', + parent_detection => 1, + parent_recursion => 5, + os_detection => 0, + recon_timing_template => 3, + recon_ports => '', + resolve_names => 0, + snmp_auth_user => '', + snmp_auth_pass => '', + snmp_auth_method => '', + snmp_checks => 2, + snmp_privacy_method => '', + snmp_privacy_pass => '', + snmp_security_level => '', + snmp_timeout => 2, + snmp_version => 1, + subnets => [], + autoconfiguration_enabled => 0, - # Store progress summary - Discovery progress view. - step => 0, - c_network_name => '', - c_network_percent => 0.0, - summary => { - SNMP => 0, - WMI => 0, - discovered => 0, - alive => 0, - not_alive => 0 - }, - @_, + # Store progress summary - Discovery progress view. + step => 0, + c_network_name => '', + c_network_percent => 0.0, + summary => { + SNMP => 0, + WMI => 0, + discovered => 0, + alive => 0, + not_alive => 0 + }, + @_, - }; + }; - # Perform some sanity checks. - die("No subnet was specified.") unless defined($self->{'subnets'}); + # Perform some sanity checks. + die("No subnet was specified.") unless defined($self->{'subnets'}); - $self = bless($self, $class); + $self = bless($self, $class); - # Check SNMP params id SNMP is enabled - if ($self->{'snmp_enabled'}) { + # Check SNMP params id SNMP is enabled + if ($self->{'snmp_enabled'}) { - # Check SNMP version - if ( $self->{'snmp_version'} ne '1' - && $self->{'snmp_version'} ne '2' - && $self->{'snmp_version'} ne '2c' - && $self->{'snmp_version'} ne '3') { - $self->{'snmp_enabled'} = 0; - $self->call('message', "SNMP version " . $self->{'snmp_version'} . " not supported (only 1, 2, 2c and 3).", 5); - } + # Check SNMP version + if ( $self->{'snmp_version'} ne '1' + && $self->{'snmp_version'} ne '2' + && $self->{'snmp_version'} ne '2c' + && $self->{'snmp_version'} ne '3') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "SNMP version " . $self->{'snmp_version'} . " not supported (only 1, 2, 2c and 3).", 5); + } - # Check the version 3 parameters - if ($self->{'snmp_version'} eq '3') { + # Check the version 3 parameters + if ($self->{'snmp_version'} eq '3') { - # Fixed some vars - $self->{'communities'} = []; + # Fixed some vars + $self->{'communities'} = []; - # SNMP v3 checks - if ( $self->{'snmp_security_level'} ne 'noAuthNoPriv' - &&$self->{'snmp_security_level'} ne 'authNoPriv' - &&$self->{'snmp_security_level'} ne 'authPriv') { - $self->{'snmp_enabled'} = 0; - $self->call('message', "Invalid SNMP security level " . $self->{'snmp_security_level'} . ".", 5); - } - if ($self->{'snmp_privacy_method'} ne 'DES' && $self->{'snmp_privacy_method'} ne 'AES') { - $self->{'snmp_enabled'} = 0; - $self->call('message', "Invalid SNMP privacy method " . $self->{'snmp_privacy_method'} . ".", 5); - } - if ($self->{'snmp_auth_method'} ne 'MD5' && $self->{'snmp_auth_method'} ne 'SHA') { - $self->{'snmp_enabled'} = 0; - $self->call('message', "Invalid SNMP authentication method " . $self->{'snmp_auth_method'} . ".", 5); - } - } else { + # SNMP v3 checks + if ( $self->{'snmp_security_level'} ne 'noAuthNoPriv' + &&$self->{'snmp_security_level'} ne 'authNoPriv' + &&$self->{'snmp_security_level'} ne 'authPriv') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP security level " . $self->{'snmp_security_level'} . ".", 5); + } + if ($self->{'snmp_privacy_method'} ne 'DES' && $self->{'snmp_privacy_method'} ne 'AES') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP privacy method " . $self->{'snmp_privacy_method'} . ".", 5); + } + if ($self->{'snmp_auth_method'} ne 'MD5' && $self->{'snmp_auth_method'} ne 'SHA') { + $self->{'snmp_enabled'} = 0; + $self->call('message', "Invalid SNMP authentication method " . $self->{'snmp_auth_method'} . ".", 5); + } + } else { - # Fixed some vars - $self->{'snmp_auth_user'} = ''; - $self->{'snmp_auth_pass'} = ''; - $self->{'snmp_auth_method'} = ''; - $self->{'snmp_privacy_method'} = ''; - $self->{'snmp_privacy_pass'} = ''; - $self->{'snmp_security_level'} = ''; + # Fixed some vars + $self->{'snmp_auth_user'} = ''; + $self->{'snmp_auth_pass'} = ''; + $self->{'snmp_auth_method'} = ''; + $self->{'snmp_privacy_method'} = ''; + $self->{'snmp_privacy_pass'} = ''; + $self->{'snmp_security_level'} = ''; - # Disable SNMP scans if no community was given. - if (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) { - $self->{'snmp_enabled'} = 0; - $self->call('message', "There is no SNMP community configured.", 5); + # Disable SNMP scans if no community was given. + if (ref($self->{'communities'}) ne "ARRAY" || scalar(@{$self->{'communities'}}) == 0) { + $self->{'snmp_enabled'} = 0; + $self->call('message', "There is no SNMP community configured.", 5); - } - } - } + } + } + } - # Prepare auth array. - # WMI could be launched with '-N' - no pass - argument. - if ($self->{'wmi_enabled'} == 1){ - if (defined($self->{'auth_strings_str'})) { - @{$self->{'auth_strings_array'}} = split(',', $self->{'auth_strings_str'}); - } + # Prepare auth array. + # WMI could be launched with '-N' - no pass - argument. + if ($self->{'wmi_enabled'} == 1){ + if (defined($self->{'auth_strings_str'})) { + @{$self->{'auth_strings_array'}} = split(',', $self->{'auth_strings_str'}); + } - # Timeout available only in linux environments. - if ($^O =~ /lin/i && defined($self->{'plugin_exec'}) && defined($self->{'wmi_timeout'})) { - $self->{'timeout_cmd'} = $self->{'plugin_exec'}.' '.$self->{'wmi_timeout'}.' '; - } - } + # Timeout available only in linux environments. + if ($^O =~ /lin/i && defined($self->{'plugin_exec'}) && defined($self->{'wmi_timeout'})) { + $self->{'timeout_cmd'} = $self->{'plugin_exec'}.' '.$self->{'wmi_timeout'}.' '; + } + } - # Remove all snmp related values if disabled - if (!$self->{'snmp_enabled'}) { - $self->{'communities'} = []; - $self->{'snmp_auth_user'} = ''; - $self->{'snmp_auth_pass'} = ''; - $self->{'snmp_auth_method'} = ''; - $self->{'snmp_privacy_method'} = ''; - $self->{'snmp_privacy_pass'} = ''; - $self->{'snmp_security_level'} = ''; - } + # Remove all snmp related values if disabled + if (!$self->{'snmp_enabled'}) { + $self->{'communities'} = []; + $self->{'snmp_auth_user'} = ''; + $self->{'snmp_auth_pass'} = ''; + $self->{'snmp_auth_method'} = ''; + $self->{'snmp_privacy_method'} = ''; + $self->{'snmp_privacy_pass'} = ''; + $self->{'snmp_security_level'} = ''; + } - return $self; + return $self; } -######################################################################################## +################################################################################ # Add an address to a device. -######################################################################################## +################################################################################ sub add_addresses($$$) { - my ($self, $device, $ip_address) = @_; + my ($self, $device, $ip_address) = @_; - $self->{'visited_devices'}->{$device}->{'addr'}->{$ip_address} = ''; + $self->{'visited_devices'}->{$device}->{'addr'}->{$ip_address} = ''; } -######################################################################################## +################################################################################ # Add a MAC/IP address to the ARP cache. -######################################################################################## +################################################################################ sub add_mac($$$) { - my ($self, $mac, $ip_addr) = @_; + my ($self, $mac, $ip_addr) = @_; - $mac = parse_mac($mac); - $self->{'arp_cache'}->{$mac} = $ip_addr; + $mac = parse_mac($mac); + $self->{'arp_cache'}->{$mac} = $ip_addr; } -######################################################################################## +################################################################################ # Add an interface/MAC to the interface cache. -######################################################################################## +################################################################################ sub add_iface($$$) { - my ($self, $iface, $mac) = @_; + my ($self, $iface, $mac) = @_; - $iface =~ s/"//g; - $self->{'ifaces'}->{$mac} = $iface; + $iface =~ s/"//g; + $self->{'ifaces'}->{$mac} = $iface; } -######################################################################################## +################################################################################ # Discover connectivity from address forwarding tables. -######################################################################################## +################################################################################ sub aft_connectivity($$) { - my ($self, $switch) = @_; - my (%mac_temp, @aft_temp); + my ($self, $switch) = @_; + my (%mac_temp, @aft_temp); - return unless ($self->is_snmp_discovered($switch)); + return unless ($self->is_snmp_discovered($switch)); - $self->enable_vlan_cache(); + $self->enable_vlan_cache(); - # Get the address forwarding table (AFT) of each switch. - my @aft; - foreach my $mac ($self->snmp_get_value_array($switch, $DOT1DTPFDBADDRESS)) { - push(@aft, parse_mac($mac)); - } + # Get the address forwarding table (AFT) of each switch. + my @aft; + foreach my $mac ($self->snmp_get_value_array($switch, $DOT1DTPFDBADDRESS)) { + push(@aft, parse_mac($mac)); + } - # Search for matching entries. - foreach my $aft_mac (@aft) { + # Search for matching entries. + foreach my $aft_mac (@aft) { - # Do we know who this is? - my $host = $self->get_ip_from_mac($aft_mac); - next unless defined($host) and $host ne ''; + # Do we know who this is? + my $host = $self->get_ip_from_mac($aft_mac); + next unless defined($host) and $host ne ''; - # Get the name of the host interface if available. - my $host_if_name = $self->get_iface($aft_mac); - $host_if_name = defined($host_if_name) ? $host_if_name : 'ping'; + # Get the name of the host interface if available. + my $host_if_name = $self->get_iface($aft_mac); + $host_if_name = defined($host_if_name) ? $host_if_name : 'Host Alive'; - # Get the interface associated to the port were we found the MAC address. - my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac); - next unless defined($switch_if_name) and ($switch_if_name ne ''); + # Get the interface associated to the port were we found the MAC address. + my $switch_if_name = $self->get_if_from_aft($switch, $aft_mac); + next unless defined($switch_if_name) and ($switch_if_name ne ''); - # Do not connect a host to a switch twice using the same interface. - # The switch is probably connected to another switch. - next if ($self->is_switch_connected($host, $host_if_name)); - $self->mark_switch_connected($host, $host_if_name); + # Do not connect a host to a switch twice using the same interface. + # The switch is probably connected to another switch. + next if ($self->is_switch_connected($host, $host_if_name)); + $self->mark_switch_connected($host, $host_if_name); - # The switch and the host are already connected. - next if ($self->are_connected($switch, $switch_if_name, $host, $host_if_name)); + # The switch and the host are already connected. + next if ($self->are_connected($switch, $switch_if_name, $host, $host_if_name)); - # Connect! - $self->mark_connected($switch, $switch_if_name, $host, $host_if_name); - $self->call('message', "Switch $switch (if $switch_if_name) is connected to host $host (if $host_if_name).", 5); - } + # Connect! + $self->mark_connected($switch, $switch_if_name, $host, $host_if_name); + $self->call('message', "Switch $switch (if $switch_if_name) is connected to host $host (if $host_if_name).", 5); + } - $self->disable_vlan_cache(); + $self->disable_vlan_cache(); } -######################################################################################## +################################################################################ # Return 1 if the given devices are connected to each other, 0 otherwise. -######################################################################################## +################################################################################ sub are_connected($$$$$) { - my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; + my ($self, $dev_1, $if_1, $dev_2, $if_2) = @_; - # Check for aliases! - $dev_1 = $self->{'aliases'}->{$dev_1} if defined($self->{'aliases'}->{$dev_1}); - $dev_2 = $self->{'aliases'}->{$dev_2} if defined($self->{'aliases'}->{$dev_2}); + # Check for aliases! + $dev_1 = $self->{'aliases'}->{$dev_1} if defined($self->{'aliases'}->{$dev_1}); + $dev_2 = $self->{'aliases'}->{$dev_2} if defined($self->{'aliases'}->{$dev_2}); - # Use ping modules when interfaces are unknown. - $if_1 = "ping" if $if_1 eq ''; - $if_2 = "ping" if $if_2 eq ''; + # Use Host Alive modules when interfaces are unknown. + $if_1 = "Host Alive" if $if_1 eq ''; + $if_2 = "Host Alive" if $if_2 eq ''; - if ( defined($self->{'connections'}->{"${dev_1}\t${if_1}\t${dev_2}\t${if_2}"}) - ||defined($self->{'connections'}->{"${dev_2}\t${if_2}\t${dev_1}\t${if_1}"})) { - return 1; - } + if ( defined($self->{'connections'}->{"${dev_1}\t${if_1}\t${dev_2}\t${if_2}"}) + ||defined($self->{'connections'}->{"${dev_2}\t${if_2}\t${dev_1}\t${if_1}"})) { + return 1; + } - return 0; + return 0; } -######################################################################################## -# Discover as much information as possible from the given device using SNMP. -######################################################################################## -sub snmp_discovery($$) { - my ($self, $device) = @_; - - # Have we already visited this device? - return if ($self->is_visited($device)); - - # Mark the device as visited. - $self->mark_visited($device); - - # Are SNMP scans enabled? - if ($self->{'snmp_enabled'} == 1) { - - # Try to find the MAC with an ARP request. - $self->get_mac_from_ip($device); - - # Check if the device responds to SNMP. - if ($self->snmp_responds($device)) { - $self->{'summary'}->{'SNMP'} += 1; - - # Fill the VLAN cache. - $self->find_vlans($device); - - # Guess the device type. - $self->guess_device_type($device); - - # Find aliases for the device. - $self->find_aliases($device); - - # Find interfaces for the device. - $self->find_ifaces($device); - - # Check remote ARP caches. - $self->remote_arp($device); - } - } +################################################################################ +# Initialize tmp pool for addr. +# Already discovered by scan_subnet. Registration only. +################################################################################ +sub icmp_discovery($$) { + my ($self, $addr) = @_; # Create an agent for the device and add it to the list of known hosts. - push(@{$self->{'hosts'}}, $device); + 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, + { + 'ip_target' => $addr, + 'name' => "Host Alive", + 'description' => '', + 'type' => 'remote_icmp_proc', + 'id_modulo' => 2, + } + ); - $self->call('create_agent', $device); } -####################################################################### +################################################################################ +# Discover as much information as possible from the given device using SNMP. +################################################################################ +sub snmp_discovery($$) { + my ($self, $device) = @_; + + # Have we already visited this device? + return if ($self->is_visited($device)); + + # Mark the device as visited. + $self->mark_visited($device); + + # Are SNMP scans enabled? + if ($self->{'snmp_enabled'} == 1) { + + # Try to find the MAC with an ARP request. + $self->get_mac_from_ip($device); + + # Check if the device responds to SNMP. + if ($self->snmp_responds($device)) { + $self->{'summary'}->{'SNMP'} += 1; + + # Fill the VLAN cache. + $self->find_vlans($device); + + # Guess the device type. + $self->guess_device_type($device); + + # Find aliases for the device. + $self->find_aliases($device); + + # Find interfaces for the device. + $self->find_ifaces($device); + + # Check remote ARP caches. + $self->remote_arp($device); + + # Get PEN. + $self->snmp_pen($device); + } + } +} + +################################################################################ # Try to call the given function on the given object. -####################################################################### +################################################################################ sub call { - my $self = shift; - my $func = shift; - my @params = @_; + my $self = shift; + my $func = shift; + my @params = @_; - if ($self->can($func)) { - $self->$func(@params); - } + if ($self->can($func)) { + $self->$func(@params); + } } -######################################################################################## +################################################################################ # Disable the VLAN cache. -######################################################################################## +################################################################################ sub disable_vlan_cache($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'__vlan_cache_enabled__'} = 0; + $self->{'__vlan_cache_enabled__'} = 0; } -######################################################################################## +################################################################################ # Enable the VLAN cache. -######################################################################################## +################################################################################ sub enable_vlan_cache($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return if ($self->{'vlan_cache_enabled'} == 0); - $self->{'__vlan_cache_enabled__'} = 1; + return if ($self->{'vlan_cache_enabled'} == 0); + $self->{'__vlan_cache_enabled__'} = 1; } -########################################################################## +################################################################################ # Connect the given hosts to its gateway. -########################################################################## +################################################################################ sub gateway_connectivity($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - my $gw = $self->get_gateway($host); - return unless defined($gw); + my $gw = $self->get_gateway($host); + return unless defined($gw); - # Check for aliases! - $host = $self->{'aliases'}->{$host} if defined($self->{'aliases'}->{$host}); - $gw = $self->{'aliases'}->{$gw} if defined($self->{'aliases'}->{$gw}); + # Check for aliases! + $host = $self->{'aliases'}->{$host} if defined($self->{'aliases'}->{$host}); + $gw = $self->{'aliases'}->{$gw} if defined($self->{'aliases'}->{$gw}); - # Same host, different IP addresses. - return if ($host eq $gw); + # Same host, different IP addresses. + return if ($host eq $gw); - $self->call('message', "Host $host is reached via gateway $gw.", 5); - $self->mark_connected($gw, '', $host, ''); + $self->call('message', "Host $host is reached via gateway $gw.", 5); + $self->mark_connected($gw, '', $host, ''); } -######################################################################################## +################################################################################ # Find IP address aliases for the given device. -######################################################################################## +################################################################################ sub find_aliases($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Get ARP cache. - my @ip_addresses = $self->snmp_get_value_array($device, $IPENTADDR); - foreach my $ip_address (@ip_addresses) { + # Get ARP cache. + my @ip_addresses = $self->snmp_get_value_array($device, $IPENTADDR); + foreach my $ip_address (@ip_addresses) { - # Skip broadcast and localhost addresses. - next if ($ip_address =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast and localhost addresses. + next if ($ip_address =~ m/\.255$|\.0$|127\.0\.0\.1$/); - # Sometimes we find the same IP address we had. - next if ($ip_address eq $device); + # Sometimes we find the same IP address we had. + next if ($ip_address eq $device); - $self->add_addresses($device, $ip_address); + $self->add_addresses($device, $ip_address); - # Try to find the MAC with an ARP request. - $self->get_mac_from_ip($ip_address); + # Try to find the MAC with an ARP request. + $self->get_mac_from_ip($ip_address); - $self->call('message', "Found address $ip_address for host $device.", 5); + $self->call('message', "Found address $ip_address for host $device.", 5); - # Is this address an alias itself? - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - next if ($ip_address eq $device); + # Is this address an alias itself? + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + next if ($ip_address eq $device); - # Link the two addresses. - $self->{'aliases'}->{$ip_address} = $device; - } + # Link the two addresses. + $self->{'aliases'}->{$ip_address} = $device; + } } -######################################################################################## +################################################################################ # Find all the interfaces for the given host. -######################################################################################## +################################################################################ sub find_ifaces($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Does it respond to SNMP? - return unless ($self->is_snmp_discovered($device)); + # Does it respond to SNMP? + return unless ($self->is_snmp_discovered($device)); - my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); - foreach my $if_index (@output) { + my @output = $self->snmp_get_value_array($device, $PandoraFMS::Recon::Base::IFINDEX); + foreach my $if_index (@output) { - next unless ($if_index =~ /^[0-9]+$/); + next unless ($if_index =~ /^[0-9]+$/); - # Ignore virtual interfaces. - next if ($self->get_if_type($device, $if_index) eq '53'); + # Ignore virtual interfaces. + next if ($self->get_if_type($device, $if_index) eq '53'); - # Get the MAC. - my $mac = $self->get_if_mac($device, $if_index); - next unless (defined($mac) && $mac ne ''); + # Get the MAC. + my $mac = $self->get_if_mac($device, $if_index); + next unless (defined($mac) && $mac ne ''); - # Save it. - $self->add_mac($mac, $device); + # Save it. + $self->add_mac($mac, $device); - # Get the name of the network interface. - my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); - next unless defined($if_name); + # Get the name of the network interface. + my $if_name = $self->snmp_get_value($device, "$PandoraFMS::Recon::Base::IFNAME.$if_index"); + next unless defined($if_name); - # Save it. - $self->add_iface($if_name, $mac); + # Save it. + $self->add_iface($if_name, $mac); - $self->call('message', "Found interface $if_name MAC $mac for host $device.", 5); - } + $self->call('message', "Found interface $if_name MAC $mac for host $device.", 5); + } } -######################################################################################## +################################################################################ # Find the device's VLANs and fill the VLAN cache. -######################################################################################## +################################################################################ sub find_vlans ($$) { - my ($self, $device) = @_; - my %vlan_hash; + my ($self, $device) = @_; + my %vlan_hash; - foreach my $vlan ($self->snmp_get_value_array($device, $VTPVLANIFINDEX)) { - next if $vlan eq '0'; - $vlan_hash{$vlan} = 1; - } - my @vlans = keys(%vlan_hash); + foreach my $vlan ($self->snmp_get_value_array($device, $VTPVLANIFINDEX)) { + next if $vlan eq '0'; + $vlan_hash{$vlan} = 1; + } + my @vlans = keys(%vlan_hash); - $self->{'vlan_cache'}->{$device} = []; - push(@{$self->{'vlan_cache'}->{$device}}, @vlans) if (scalar(@vlans) > 0); + $self->{'vlan_cache'}->{$device} = []; + push(@{$self->{'vlan_cache'}->{$device}}, @vlans) if (scalar(@vlans) > 0); } -######################################################################################## +################################################################################ # Return the addresses of the given device as an array. -######################################################################################## +################################################################################ sub get_addresses($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - if (defined($self->{'visited_devices'}->{$device})) { - return keys(%{$self->{'visited_devices'}->{$device}->{'addr'}}); - } + if (defined($self->{'visited_devices'}->{$device})) { + return keys(%{$self->{'visited_devices'}->{$device}->{'addr'}}); + } - # By default return the given address. - return ($device); + # By default return the given address. + return ($device); } -######################################################################################## +################################################################################ # Return a device structure from an IP address. -######################################################################################## +################################################################################ sub get_device($$) { - my ($self, $addr) = @_; + my ($self, $addr) = @_; - if (defined($self->{'visited_devices'}->{$addr})) { - return $self->{'visited_devices'}->{$addr}; - } + if (defined($self->{'visited_devices'}->{$addr})) { + return $self->{'visited_devices'}->{$addr}; + } - return undef; + return undef; } -######################################################################################## +################################################################################ # Get the SNMP community of the given device. Returns undef if no community was found. -######################################################################################## +################################################################################ sub get_community($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return '' if ($self->{'snmp_version'} eq "3"); + return '' if ($self->{'snmp_version'} eq "3"); - if (defined($self->{'community_cache'}->{$device})) { - return $self->{'community_cache'}->{$device}; - } + if (defined($self->{'community_cache'}->{$device})) { + return $self->{'community_cache'}->{$device}; + } - return ''; + return ''; } -######################################################################################## +################################################################################ # Return the connection hash. -######################################################################################## +################################################################################ sub get_connections($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'connections'}; + return $self->{'connections'}; } -######################################################################################## +################################################################################ +# Return the PEN associated to target host. +################################################################################ +sub get_pen($$) { + my ($self, $host) = @_; + + return undef unless ref($self->{'pen'}) eq 'HASH'; + + return $self->{'pen'}->{$host}; +} + +################################################################################ # Return the parent relationship hash. -######################################################################################## +################################################################################ sub get_parents($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'parents'}; + return $self->{'parents'}; } -######################################################################################## +################################################################################ # Get the type of the given device. -######################################################################################## +################################################################################ sub get_device_type($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - if (defined($self->{'visited_devices'}->{$device})) { - return $self->{'visited_devices'}->{$device}->{'type'}; - } + if (defined($self->{'visited_devices'}->{$device})) { + if (defined($self->{'visited_devices'}->{$device}->{'type'})) { + return $self->{'visited_devices'}->{$device}->{'type'}; + } else { + $self->{'visited_devices'}->{$device}->{'type'} = 'host'; + } + } - # Assume 'host' by default. - return 'host'; + # Assume 'host' by default. + return 'host'; } -######################################################################################## +################################################################################ # Return all known hosts that are not switches or routers. -######################################################################################## +################################################################################ sub get_hosts($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'hosts'}; + return $self->{'hosts'}; } -######################################################################################## +################################################################################ # Add an interface/MAC to the interface cache. -######################################################################################## +################################################################################ sub get_iface($$) { - my ($self, $mac) = @_; + my ($self, $mac) = @_; - return undef unless defined($self->{'ifaces'}->{$mac}); + return undef unless defined($self->{'ifaces'}->{$mac}); - return $self->{'ifaces'}->{$mac}; + return $self->{'ifaces'}->{$mac}; } -######################################################################################## +################################################################################ # Get an interface name from an AFT entry. Returns undef on error. -######################################################################################## +################################################################################ sub get_if_from_aft($$$) { - my ($self, $switch, $mac) = @_; + my ($self, $switch, $mac) = @_; - # Get the port associated to the MAC. - my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); - return '' unless defined($port); + # Get the port associated to the MAC. + my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); + return '' unless defined($port); - # Get the interface index associated to the port. - my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); - return '' unless defined($if_index); + # Get the interface index associated to the port. + my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); + return '' unless defined($if_index); - # Get the interface name. - my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); - return "if$if_index" unless defined($if_name); + # Get the interface name. + my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); + return "if$if_index" unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } -######################################################################################## +################################################################################ # Get an interface name from an IP address. -######################################################################################## +################################################################################ sub get_if_from_ip($$$) { - my ($self, $device, $ip_addr) = @_; + my ($self, $device, $ip_addr) = @_; - # Get the port associated to the IP address. - my $if_index = $self->snmp_get_value($device, "$IPROUTEIFINDEX.$ip_addr"); - return '' unless defined($if_index); + # Get the port associated to the IP address. + my $if_index = $self->snmp_get_value($device, "$IPROUTEIFINDEX.$ip_addr"); + return '' unless defined($if_index); - # Get the name of the interface associated to the port. - my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); - return '' unless defined($if_name); + # Get the name of the interface associated to the port. + my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); + return '' unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } -######################################################################################## +################################################################################ # Get an interface name from a MAC address. -######################################################################################## +################################################################################ sub get_if_from_mac($$$) { - my ($self, $device, $mac) = @_; + my ($self, $device, $mac) = @_; - # Get the port associated to the IP address. - my @output = $self->snmp_get($device, $IFPHYSADDRESS); - foreach my $line (@output) { - chomp($line); - next unless $line =~ /^IFPHYSADDRESS.(\S+)\s+=\s+\S+:\s+(.*)$/; - my ($if_index, $if_mac) = ($1, $2); + # Get the port associated to the IP address. + my @output = $self->snmp_get($device, $IFPHYSADDRESS); + foreach my $line (@output) { + chomp($line); + next unless $line =~ /^IFPHYSADDRESS.(\S+)\s+=\s+\S+:\s+(.*)$/; + my ($if_index, $if_mac) = ($1, $2); - # Make sure the MAC addresses match. - next unless (mac_matches($mac, $if_mac) == 1); + # Make sure the MAC addresses match. + next unless (mac_matches($mac, $if_mac) == 1); - # Pupulate the ARP cache. - $self->add_mac($mac, $device); + # Pupulate the ARP cache. + $self->add_mac($mac, $device); - # Get the name of the interface associated to the port. - my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); - return '' unless defined($if_name); + # Get the name of the interface associated to the port. + my $if_name = $self->snmp_get_value($device, "$IFNAME.$if_index"); + return '' unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; - } + $if_name =~ s/"//g; + return $if_name; + } - return ''; + return ''; } -######################################################################################## +################################################################################ # Get an interface name from a port number. Returns '' on error. -######################################################################################## +################################################################################ sub get_if_from_port($$$) { - my ($self, $switch, $port) = @_; + my ($self, $switch, $port) = @_; - # Get the interface index associated to the port. - my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); - return '' unless defined($if_index); + # Get the interface index associated to the port. + my $if_index = $self->snmp_get_value($switch, "$DOT1DBASEPORTIFINDEX.$port"); + return '' unless defined($if_index); - # Get the interface name. - my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); - return "if$if_index" unless defined($if_name); + # Get the interface name. + my $if_name = $self->snmp_get_value($switch, "$IFNAME.$if_index"); + return "if$if_index" unless defined($if_name); - $if_name =~ s/"//g; - return $if_name; + $if_name =~ s/"//g; + return $if_name; } -######################################################################################## +################################################################################ # Returns the IP address of the given interface (by index). -######################################################################################## +################################################################################ sub get_if_ip($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my @output = $self->snmp_get($device, $IPADENTIFINDEX); - foreach my $line (@output) { - chomp($line); - return $1 if ($line =~ m/^$IPADENTIFINDEX.(\S+)\s+=\s+\S+:\s+$if_index$/); - } + my @output = $self->snmp_get($device, $IPADENTIFINDEX); + foreach my $line (@output) { + chomp($line); + return $1 if ($line =~ m/^$IPADENTIFINDEX.(\S+)\s+=\s+\S+:\s+$if_index$/); + } - return ''; + return ''; } -######################################################################################## +################################################################################ # Returns the MAC address of the given interface (by index). -######################################################################################## +################################################################################ sub get_if_mac($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my $mac = $self->snmp_get_value($device, "$IFPHYSADDRESS.$if_index"); - return '' unless defined($mac); + my $mac = $self->snmp_get_value($device, "$IFPHYSADDRESS.$if_index"); + return '' unless defined($mac); - # Clean-up the MAC address. - $mac = parse_mac($mac); + # Clean-up the MAC address. + $mac = parse_mac($mac); - return $mac; + return $mac; } -######################################################################################## +################################################################################ # Returns the type of the given interface (by index). -######################################################################################## +################################################################################ sub get_if_type($$$) { - my ($self, $device, $if_index) = @_; + my ($self, $device, $if_index) = @_; - my $type = $self->snmp_get_value($device, "$IFTYPE.$if_index"); - return '' unless defined($type); + my $type = $self->snmp_get_value($device, "$IFTYPE.$if_index"); + return '' unless defined($type); - return $type; + return $type; } -######################################################################################## +################################################################################ # Get an IP address from the ARP cache given the MAC address. -######################################################################################## +################################################################################ sub get_ip_from_mac($$) { - my ($self, $mac_addr) = @_; + my ($self, $mac_addr) = @_; - if (defined($self->{'arp_cache'}->{$mac_addr})) { - return $self->{'arp_cache'}->{$mac_addr}; - } + if (defined($self->{'arp_cache'}->{$mac_addr})) { + return $self->{'arp_cache'}->{$mac_addr}; + } - return undef; + return undef; } -######################################################################################## +################################################################################ # Attemtps to find -######################################################################################## +################################################################################ sub get_mac_from_ip($$) { - my ($self, $host) = @_; - my $mac = undef; + my ($self, $host) = @_; + my $mac = undef; - eval { - $mac = `arping -c 1 -r $host 2>$DEVNULL`; - $mac = undef unless ($? == 0); - }; + eval { + $mac = `arping -c 1 $host 2>$DEVNULL`; + $mac = undef unless ($? == 0); + }; - return unless defined($mac); + return unless defined($mac); - # Clean-up the MAC address. - chomp($mac); - $mac = parse_mac($mac); - $self->add_mac($mac, $host); + ($mac) = $mac =~ /\[(.*?)\]/ if defined($mac); - $self->call('message', "Found MAC $mac for host $host in the local ARP cache.", 5); + # Clean-up the MAC address. + chomp($mac); + $mac = parse_mac($mac); + $self->add_mac($mac, $host); + + $self->call('message', "Found MAC $mac for host $host in the local ARP cache.", 5); } -######################################################################################## +################################################################################ # Get a port number from an AFT entry. Returns undef on error. -######################################################################################## +################################################################################ sub get_port_from_aft($$$) { - my ($self, $switch, $mac) = @_; + my ($self, $switch, $mac) = @_; - # Get the port associated to the MAC. - my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); - return '' unless defined($port); + # Get the port associated to the MAC. + my $port = $self->snmp_get_value($switch, "$DOT1DTPFDBPORT." . mac_to_dec($mac)); + return '' unless defined($port); - return $port; + return $port; } -######################################################################################## +################################################################################ # Fill the route cache. -######################################################################################## +################################################################################ sub get_routes($) { - my ($self) = @_; + my ($self) = @_; - # Empty the current route cache. - $self->{'routes'} = []; + # Empty the current route cache. + $self->{'routes'} = []; - # Parse route's output. - my @output = `route -n 2>$DEVNULL`; - foreach my $line (@output) { - chomp($line); - if ($line =~ /^0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+).*/) { - $self->{'default_gw'} = $1; - } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+).*/) { - push(@{$self->{'routes'}}, { dest => $1, gw => $2, mask => $3 }); - } - } + # Parse route's output. + my @output = `route -n 2>$DEVNULL`; + foreach my $line (@output) { + chomp($line); + if ($line =~ /^0\.0\.0\.0\s+(\d+\.\d+\.\d+\.\d+).*/) { + $self->{'default_gw'} = $1; + } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+)\s+(\d+\.\d+\.\d+\.\d+).*/) { + push(@{$self->{'routes'}}, { dest => $1, gw => $2, mask => $3 }); + } + } - # Replace 0.0.0.0 with the default gateway's IP. - return unless defined($self->{'default_gw'}); - foreach my $route (@{$self->{'routes'}}) { - $route->{gw} = $self->{'default_gw'} if ($route->{'gw'} eq '0.0.0.0'); - } + # Replace 0.0.0.0 with the default gateway's IP. + return unless defined($self->{'default_gw'}); + foreach my $route (@{$self->{'routes'}}) { + $route->{gw} = $self->{'default_gw'} if ($route->{'gw'} eq '0.0.0.0'); + } } -######################################################################################## +################################################################################ # Get the gateway to reach the given host. -######################################################################################## +################################################################################ sub get_gateway($) { - my ($self, $host) = @_; + my ($self, $host) = @_; - # Look for a specific route to the given host. - foreach my $route (@{$self->{'routes'}}) { - if (subnet_matches($host, $route->{'dest'}, $route->{'mask'})) { - return $route->{'gw'}; - } - } + # Look for a specific route to the given host. + foreach my $route (@{$self->{'routes'}}) { + if (subnet_matches($host, $route->{'dest'}, $route->{'mask'})) { + return $route->{'gw'}; + } + } - # Return the default gateway. - return $self->{'default_gw'} if defined($self->{'default_gw'}); + # Return the default gateway. + return $self->{'default_gw'} if defined($self->{'default_gw'}); - # Ops! - return undef; + # Ops! + return undef; } -######################################################################################## +################################################################################ # Return a pointer to an array containing configured subnets. -######################################################################################## +################################################################################ sub get_subnets($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'subnets'}; + return $self->{'subnets'}; } -######################################################################################## +################################################################################ # Get an array of all the visited devices. # NOTE: This functions returns the whole device structures, not just address # like get_hosts, get_switches, get_routers and get_all_devices. -######################################################################################## +################################################################################ sub get_visited_devices($) { - my ($self) = @_; + my ($self) = @_; - return $self->{'visited_devices'}; + return $self->{'visited_devices'}; } -######################################################################################## +################################################################################ # Returns an array of found VLAN IDs. -######################################################################################## +################################################################################ sub get_vlans($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Disabled in verison 3 - return () if ($self->{'snmp_version'} eq "3"); + # Disabled in verison 3 + return () if ($self->{'snmp_version'} eq "3"); - # Is the VLAN cache disabled? - return () unless ($self->{'__vlan_cache_enabled__'} == 1); + # Is the VLAN cache disabled? + return () unless ($self->{'__vlan_cache_enabled__'} == 1); - return () unless defined($self->{'vlan_cache'}->{$device}); + return () unless defined($self->{'vlan_cache'}->{$device}); - return @{$self->{'vlan_cache'}->{$device}}; + return @{$self->{'vlan_cache'}->{$device}}; } -######################################################################################## +################################################################################ # Guess the type of the given device. -######################################################################################## +################################################################################ sub guess_device_type($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Get the value of sysServices. - my $services = $self->snmp_get_value($device, "$SYSSERVICES.0"); - return unless defined($services); + # Get the value of sysServices. + my $services = $self->snmp_get_value($device, "$SYSSERVICES.0"); + return unless defined($services); - # Check the individual bits. - my @service_bits = split('', unpack('b8', pack('C', $services))); + # Check the individual bits. + my @service_bits = split('', unpack('b8', pack('C', $services))); - # Check for layer 2 connectivity support. - my $bridge_mib = $self->snmp_get_value($device, $DOT1DBASEBRIDGEADDRESS); + # Check for layer 2 connectivity support. + my $bridge_mib = $self->snmp_get_value($device, $DOT1DBASEBRIDGEADDRESS); - # L2? - my $device_type; - if ($service_bits[1] == 1) { + # L2? + my $device_type; + if ($service_bits[1] == 1) { - # L3? - if ($service_bits[2] == 1) { + # L3? + if ($service_bits[2] == 1) { - # Bridge MIB? - if (defined($bridge_mib)) { - $device_type = 'switch'; - } else { + # Bridge MIB? + if (defined($bridge_mib)) { + $device_type = 'switch'; + } else { - # L7? - if ($service_bits[6] == 1) { - $device_type = 'host'; - } else { - $device_type = 'router'; - } - } - }else { + # L7? + if ($service_bits[6] == 1) { + $device_type = 'host'; + } else { + $device_type = 'router'; + } + } + }else { - # Bridge MIB? - if (defined($bridge_mib)) { - $device_type = 'switch'; - } else { - $device_type = 'host'; - } - } - }else { + # Bridge MIB? + if (defined($bridge_mib)) { + $device_type = 'switch'; + } else { + $device_type = 'host'; + } + } + }else { - # L3? - if ($service_bits[2] == 1) { + # L3? + if ($service_bits[2] == 1) { - # L4? - if ($service_bits[3] == 1) { - $device_type = 'switch'; - } else { + # L4? + if ($service_bits[3] == 1) { + $device_type = 'switch'; + } else { - # L7? - if ($service_bits[6] == 1) { - $device_type = 'host'; - } else { - $device_type = 'router'; - } - } - }else { + # L7? + if ($service_bits[6] == 1) { + $device_type = 'host'; + } else { + $device_type = 'router'; + } + } + }else { - # Printer MIB? - my $printer_mib = $self->snmp_get_value($device, $PRTMARKERINDEX); - if (defined($printer_mib)) { - $device_type = 'printer'; - } else { - $device_type = 'host'; - } - } - } + # Printer MIB? + my $printer_mib = $self->snmp_get_value($device, $PRTMARKERINDEX); + if (defined($printer_mib)) { + $device_type = 'printer'; + } else { + $device_type = 'host'; + } + } + } - # Set the type of the device. - $self->set_device_type($device, $device_type); + # Set the type of the device. + $self->set_device_type($device, $device_type); } -######################################################################################## +################################################################################ # Return 1 if the given device has children. -######################################################################################## +################################################################################ sub has_children($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if (defined($self->{'children'}->{$device})); + return 1 if (defined($self->{'children'}->{$device})); - return 0; + return 0; } -######################################################################################## +################################################################################ # Return 1 if the given device has a parent. -######################################################################################## +################################################################################ sub has_parent($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if (defined($self->{'parents'}->{$device})); + return 1 if (defined($self->{'parents'}->{$device})); - return 0; + return 0; } -######################################################################################## +################################################################################ # Returns 1 if the device belongs to one of the scanned subnets. -######################################################################################## +################################################################################ sub in_subnet($$) { - my ($self, $device) = @_; - $device = ip_to_long($device); + my ($self, $device) = @_; + $device = ip_to_long($device); - # No subnets specified. - return 1 if (scalar(@{$self->{'subnets'}}) <= 0); + # No subnets specified. + return 1 if (scalar(@{$self->{'subnets'}}) <= 0); - foreach my $subnet (@{$self->{'subnets'}}) { - if (subnet_matches($device, $subnet)) { - return 1; - } - } + foreach my $subnet (@{$self->{'subnets'}}) { + if (subnet_matches($device, $subnet)) { + return 1; + } + } - return 0; + return 0; } -########################################################################## +################################################################################ # Check for switches that are connected to other switches/routers and show # up in a switch/router's port. -########################################################################## +################################################################################ sub is_switch_connected($$$) { - my ($self, $device, $iface) = @_; + my ($self, $device, $iface) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - return 1 if defined($self->{'switch_to_switch'}->{"${device}\t${iface}"}); + return 1 if defined($self->{'switch_to_switch'}->{"${device}\t${iface}"}); - return 0; + return 0; } -######################################################################################## +################################################################################ # Returns 1 if the given device has already been visited, 0 otherwise. -######################################################################################## +################################################################################ sub is_visited($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - if (defined($self->{'visited_devices'}->{$device})) { - return 1; - } + if (defined($self->{'visited_devices'}->{$device})) { + return 1; + } - return 0; + return 0; } -######################################################################################## +################################################################################ # Returns 1 if the given device has responded successfully to a snmp request # Returns 0 otherwise. -######################################################################################## +################################################################################ sub is_snmp_discovered($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Check if device is into discovered cache - return (defined($self->{'discovered_cache'}->{$device})) ? 1 : 0; + # Check if device is into discovered cache + return (defined($self->{'discovered_cache'}->{$device})) ? 1 : 0; } -######################################################################################## +################################################################################ # Mark the given devices as connected to each other on the given interfaces. -######################################################################################## +################################################################################ sub mark_connected($$;$$$) { - my ($self, $parent, $parent_if, $child, $child_if) = @_; + my ($self, $parent, $parent_if, $child, $child_if) = @_; - # Check for aliases! - $parent = $self->{'aliases'}->{$parent} if defined($self->{'aliases'}->{$parent}); - $child = $self->{'aliases'}->{$child} if defined($self->{'aliases'}->{$child}); + # Check for aliases! + $parent = $self->{'aliases'}->{$parent} if defined($self->{'aliases'}->{$parent}); + $child = $self->{'aliases'}->{$child} if defined($self->{'aliases'}->{$child}); - # Use ping modules when interfaces are unknown. - $parent_if = "ping" if $parent_if eq ''; - $child_if = "ping" if $child_if eq ''; + # Use ping modules when interfaces are unknown. + $parent_if = "Host Alive" if $parent_if eq ''; + $child_if = "Host Alive" if $child_if eq ''; - # Do not connect devices using ping modules. A parent-child relationship is enough. - if ($parent_if ne "ping" || $child_if ne "ping") { - $self->{'connections'}->{"${parent}\t${parent_if}\t${child}\t${child_if}"} = 1; - $self->call('connect_agents', $parent, $parent_if, $child, $child_if); - } + # Do not connect devices using ping modules. A parent-child relationship is enough. + if ($parent_if ne "Host Alive" || $child_if ne "Host Alive") { + $self->{'connections'}->{"${parent}\t${parent_if}\t${child}\t${child_if}"} = 1; + $self->call('connect_agents', $parent, $parent_if, $child, $child_if); + } - # Prevent parent-child loops. - if (!defined($self->{'parents'}->{$parent}) - ||$self->{'parents'}->{$parent} ne $child) { + # Prevent parent-child loops. + if (!defined($self->{'parents'}->{$parent}) + ||$self->{'parents'}->{$parent} ne $child) { - # A parent-child relationship is always created to help complete the map with - # layer 3 information. - $self->{'parents'}->{$child} = $parent; - $self->{'children'}->{$parent} = $child; - $self->call('set_parent', $child, $parent); - } + # A parent-child relationship is always created to help complete the map with + # layer 3 information. + $self->{'parents'}->{$child} = $parent; + $self->{'children'}->{$parent} = $child; + $self->call('set_parent', $child, $parent); + } } -######################################################################################## +################################################################################ # Mark the given switch as having a connection on the given interface. -######################################################################################## +################################################################################ sub mark_switch_connected($$$) { - my ($self, $device, $iface) = @_; + my ($self, $device, $iface) = @_; - # Check for aliases! - $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); - $self->{'switch_to_switch'}->{"${device}\t${iface}"} = 1; + # Check for aliases! + $device = $self->{'aliases'}->{$device} if defined($self->{'aliases'}->{$device}); + $self->{'switch_to_switch'}->{"${device}\t${iface}"} = 1; } -######################################################################################## +################################################################################ # Mark the given device as visited. -######################################################################################## +################################################################################ sub mark_visited($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'visited_devices'}->{$device} = { - 'addr' => { $device => '' }, - 'type' => 'host' - }; + $self->{'visited_devices'}->{$device} = { + 'addr' => { $device => '' }, + 'type' => 'host' + }; } -######################################################################################## +################################################################################ # Mark the given device as snmp discovered. -######################################################################################## +################################################################################ sub mark_discovered($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - $self->{'discovered_cache'}->{$device} = 1; + $self->{'discovered_cache'}->{$device} = 1; } -######################################################################################## +################################################################################ # Validate the configuration for the given device. # Returns 1 if successfull snmp contact, 0 otherwise. # Updates the SNMP community cache on v1, v2 and v2c. -######################################################################################## +################################################################################ sub snmp_responds($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - return 1 if($self->is_snmp_discovered($device)); + return 1 if($self->is_snmp_discovered($device)); - return ($self->{'snmp_version'} eq "3") - ? $self->snmp_responds_v3($device) - : $self->snmp_responds_v122c($device); + return ($self->{'snmp_version'} eq "3") + ? $self->snmp_responds_v3($device) + : $self->snmp_responds_v122c($device); } -######################################################################################## +################################################################################ # Looks for a working SNMP community for the given device. Returns 1 if one is # found, 0 otherwise. Updates the SNMP community cache. -######################################################################################## +################################################################################ sub snmp_responds_v122c($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - foreach my $community (@{$self->{'communities'}}) { + foreach my $community (@{$self->{'communities'}}) { - # Clean blanks. - $community =~ s/\s+//g; + # Clean blanks. + $community =~ s/\s+//g; - my $command = $self->snmp_get_command($device, ".0", $community); - `$command`; - if ($? == 0) { - $self->set_community($device, $community); - $self->mark_discovered($device); - return 1; - } - } + my $command = $self->snmp_get_command($device, ".0", $community); + `$command`; + if ($? == 0) { + $self->set_community($device, $community); + $self->mark_discovered($device); + return 1; + } + } - return 0; + return 0; } -######################################################################################## +################################################################################ # Validate the SNMP v3 configuration for a device. # Returns 1 if successfull snmp contact, 0 otherwise. -######################################################################################## +################################################################################ sub snmp_responds_v3($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - my $command = $self->snmp_get_command($device, ".0"); - `$command`; + my $command = $self->snmp_get_command($device, ".0"); + `$command`; - if ($? == 0) { - $self->mark_discovered($device); - return 1; - } + if ($? == 0) { + $self->mark_discovered($device); + return 1; + } - return 0; + return 0; } -############################################################################## +################################################################################ # Parse the local ARP cache. -############################################################################## +################################################################################ sub local_arp($) { - my ($self) = @_; + my ($self) = @_; - my @output = `arp -an 2>$DEVNULL`; - foreach my $line (@output) { - next unless ($line =~ m/\((\S+)\) at ([0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)/); - $self->add_mac(parse_mac($2), $1); - } + my @output = `arp -an 2>$DEVNULL`; + foreach my $line (@output) { + next unless ($line =~ m/\((\S+)\) at ([0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+:[0-9a-f]+)/); + $self->add_mac(parse_mac($2), $1); + } } -############################################################################## +################################################################################ # Parse remote SNMP ARP caches. -############################################################################## +################################################################################ sub remote_arp($$) { - my ($self, $device) = @_; + my ($self, $device) = @_; - # Try to learn more MAC addresses from the device's ARP cache. - my @output = $self->snmp_get($device, $IPNETTOMEDIAPHYSADDRESS); - foreach my $line (@output) { - next unless ($line =~ /^$IPNETTOMEDIAPHYSADDRESS\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); - my ($ip_addr, $mac_addr) = ($1, $2); + # Try to learn more MAC addresses from the device's ARP cache. + my @output = $self->snmp_get($device, $IPNETTOMEDIAPHYSADDRESS); + foreach my $line (@output) { + next unless ($line =~ /^$IPNETTOMEDIAPHYSADDRESS\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); + my ($ip_addr, $mac_addr) = ($1, $2); - # Skip broadcast, net and local addresses. - next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast, net and local addresses. + next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); - $mac_addr = parse_mac($mac_addr); - $self->add_mac($mac_addr, $ip_addr); - $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache of host $device.", 5); - } + $mac_addr = parse_mac($mac_addr); + $self->add_mac($mac_addr, $ip_addr); + $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache of host $device.", 5); + } - # Look in atPhysAddress for MAC addresses too. - @output = $self->snmp_get($device, $ATPHYSADDRESS); - foreach my $line (@output) { - next unless ($line =~ m/^$ATPHYSADDRESS\.\d+\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); - my ($ip_addr, $mac_addr) = ($1, $2); + # Look in atPhysAddress for MAC addresses too. + @output = $self->snmp_get($device, $ATPHYSADDRESS); + foreach my $line (@output) { + next unless ($line =~ m/^$ATPHYSADDRESS\.\d+\.\d+\.(\S+)\s+=\s+\S+:\s+(.*)$/); + my ($ip_addr, $mac_addr) = ($1, $2); - # Skip broadcast, net and local addresses. - next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); + # Skip broadcast, net and local addresses. + next if ($ip_addr =~ m/\.255$|\.0$|127\.0\.0\.1$/); - $mac_addr = parse_mac($mac_addr); - $self->add_mac($mac_addr, $ip_addr); - $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache (atPhysAddress) of host $device.", 5); - } + $mac_addr = parse_mac($mac_addr); + $self->add_mac($mac_addr, $ip_addr); + $self->call('message', "Found MAC $mac_addr for host $ip_addr in the ARP cache (atPhysAddress) of host $device.", 5); + } } -############################################################################## -# Ping the given host. Returns 1 if the host is alive, 0 otherwise. -############################################################################## -sub ping ($$$) { - my ($self, $host) = @_; - my ($timeout, $retries, $packets) = ($self->{'icmp_timeout'},$self->{'icmp_checks'},1,); +################################################################################ +# Add agent to pool (will be registered at the end of the scan). +################################################################################ +sub prepare_agent($$) { + my ($self, $addr) = @_; + $self->{'agents_found'} = {} if ref($self->{'agents_found'}) ne 'HASH'; - # Windows - if (($^O eq "MSWin32") || ($^O eq "MSWin32-x64") || ($^O eq "cygwin")){ - $timeout *= 1000; # Convert the timeout to milliseconds. - for (my $i = 0; $i < $retries; $i++) { - my $output = `ping -n $packets -w $timeout $host`; - return 1 if ($output =~ /TTL/); - } + # Already initialized. + return if ref($self->{'agents_found'}->{$addr}) eq 'HASH'; - return 0; - } - - # Solaris - if ($^O eq "solaris"){ - my $ping_command = $host =~ /\d+:|:\d+/ ? "ping -A inet6" : "ping"; - for (my $i = 0; $i < $retries; $i++) { - - # Note: There is no timeout option. - `$ping_command -s -n $host 56 $packets >$DEVNULL 2>&1`; - return 1 if ($? == 0); - } - - return 0; - } - - # FreeBSD - if ($^O eq "freebsd"){ - my $ping_command = $host =~ /\d+:|:\d+/ ? "ping6" : "ping -t $timeout"; - for (my $i = 0; $i < $retries; $i++) { - - # Note: There is no timeout option for ping6. - `$ping_command -q -n -c $packets $host >$DEVNULL 2>&1`; - return 1 if ($? == 0); - } - - return 0; - } - - # NetBSD - if ($^O eq "netbsd"){ - my $ping_command = $host =~ /\d+:|:\d+/ ? "ping6" : "ping -w $timeout"; - for (my $i = 0; $i < $retries; $i++) { - - # Note: There is no timeout option for ping6. - `$ping_command -q -n -c $packets $host >$DEVNULL 2>&1`; - if ($? == 0) { - return 1; - } - } - - return 0; - } - - # Assume Linux by default. - my $ping_command = $host =~ /\d+:|:\d+/ ? "ping6" : "ping"; - for (my $i = 0; $i < $retries; $i++) { - `$ping_command -q -W $timeout -n -c $packets $host >$DEVNULL 2>&1`; - return 1 if ($? == 0); - } - - return 0; + $self->{'agents_found'}->{$addr} = { + 'agent' => { + 'nombre' => $addr, + 'direccion' => $addr, + 'alias' => $addr, + }, + 'pen' => $self->{'pen'}{$addr}, + 'modules' => [], + }; } -########################################################################## +################################################################################ +# Add agent to pool (will be registered at the end of the scan). +################################################################################ +sub add_agent($$) { + my ($self, $addr) = @_; + + # Avoid create empty agents. + return if is_empty($addr); + + $self->prepare_agent($addr); +} + +################################################################################ +# Add module to agent (tmp pool) (will be registered at the end of the scan). +################################################################################ +sub add_module($$$) { + my ($self, $agent, $data) = @_; + + $self->prepare_agent($agent); + + $self->{'agents_found'}->{$agent}->{'modules'} = {} + unless ref($self->{'agents_found'}->{$agent}->{'modules'}) eq 'HASH'; + + # Test module. Is it well defined? + return unless ref($data) eq 'HASH' && defined($data->{'name'}) + && $data->{'name'} ne ''; + + # Test module. Is it success? Some components have MIB name instead OID. + $self->{'translate_snmp'} = 1; + my $rs = $self->call('test_module', $agent, $data); + $self->{'translate_snmp'} = 0; + + return unless is_enabled($rs); + + $self->{'agents_found'}->{$agent}->{'modules'}{$data->{'name'}} = $data; + +} + +################################################################################ +# Test target address (methods). +################################################################################ +sub test_capabilities($$) { + my ($self, $addr) = @_; + + $self->icmp_discovery($addr); + + if (is_enabled($self->{'snmp_enabled'})) { + # SNMP discovery. + $self->snmp_discovery($addr); + } + + # WMI discovery. + if (is_enabled($self->{'wmi_enabled'})) { + # Add wmi scan if enabled. + $self->wmi_discovery($addr); + } +} + +################################################################################ # Scan the given subnet. -########################################################################## +################################################################################ sub scan_subnet($) { - my ($self) = @_; - my $progress = 1; + my ($self) = @_; + my $progress = 1; - my @subnets = @{$self->get_subnets()}; - foreach my $subnet (@subnets) { - $self->{'c_network_percent'} = 0; - $self->{'c_network_name'} = $subnet; + my @subnets = @{$self->get_subnets()}; + foreach my $subnet (@subnets) { + $self->{'c_network_percent'} = 0; + $self->{'c_network_name'} = $subnet; + $self->call('update_progress', ceil($progress)); - # Clean blanks. - $subnet =~ s/\s+//g; + # Clean blanks. + $subnet =~ s/\s+//g; - my $net_addr = new NetAddr::IP($subnet); - if (!defined($net_addr)) { - $self->call('message', "Invalid network: $subnet", 3); - next; - } + my $net_addr = new NetAddr::IP($subnet); + if (!defined($net_addr)) { + $self->call('message', "Invalid network: $subnet", 3); + next; + } - # Save the network and broadcast addresses. - my $network = $net_addr->network(); - my $broadcast = $net_addr->broadcast(); + # Save the network and broadcast addresses. + my $network = $net_addr->network(); + my $broadcast = $net_addr->broadcast(); - # fping scan. - if (-x $self->{'fping'} && $net_addr->num() > 1) { - $self->call('message', "Calling fping...", 5); + my @hosts = map { (split('/', $_))[0] } $net_addr->hostenum; + my $total_hosts = scalar(@hosts); + my %hosts_alive = (); - my @hosts = `"$self->{'fping'}" -ga "$subnet" 2>DEVNULL`; - next if (scalar(@hosts) == 0); + # By default 200, (20 * 10) + my $host_block_size = $self->{'block_size'}; - $self->{'summary'}->{'discovered'} += scalar(@hosts); + $host_block_size = 50 unless defined($self->{'block_size'}); - my $step = 50.0 / scalar(@subnets) / scalar(@hosts); # The first 50% of the recon task approx. - my $subnet_step = 100.0 / scalar(@hosts); - foreach my $line (@hosts) { - chomp($line); + # The first 50% of the recon task approx. + my $step = 25.0 / scalar(@subnets) / (($total_hosts / $host_block_size)+1); + my $subnet_step = 50.0 / (($total_hosts / $host_block_size)+1); - my @temp = split(/ /, $line); - if (scalar(@temp) != 1) { + for (my $block_index=0; + $block_index < $total_hosts; + $block_index += $host_block_size + ) { + # Update the recon task + # Increase self summary.alive hosts. + $self->call('message', "Searching for hosts (".$block_index." / ".$total_hosts.")", 5); + my $to = $host_block_size + $block_index; + $to = $total_hosts if $to >= $total_hosts; - # Junk is shown for broadcast addresses. - # Increase summary.not_alive hosts. - $self->{'summary'}->{'not_alive'} += 1; - next; - } - my $host = $temp[0]; + my $c_block_size = $to - $block_index; + my @block = pandora_block_ping( + { + 'fping' => $self->{'fping'}, + 'networktimeout' => 0.5 # use fping defaults + }, + @hosts[$block_index .. $to - 1] + ); - # Skip network and broadcast addresses. - next if ($host eq $network->addr() || $host eq $broadcast->addr()); + # check alive hosts in current block + %hosts_alive = ( + %hosts_alive, + map {chomp; $_ => 1} @block + ); - # Increase self summary.alive hosts. - $self->{'summary'}->{'alive'} += 1; - $self->call('message', "Scanning host: $host", 5); - $self->call('update_progress', ceil($progress)); - $progress += $step; - $self->{'c_network_percent'} += $subnet_step; + $self->{'summary'}->{'not_alive'} += $c_block_size - (scalar @block); + $self->{'summary'}->{'alive'} += scalar @block; - $self->snmp_discovery($host); + # Update progress. + $progress += $step; + $self->{'c_network_percent'} += $subnet_step; - # Add wmi scan if enabled. - $self->wmi_scan($host) if ($self->{'wmi_enabled'} == 1); - } - } + # Populate. + $self->call('update_progress', ceil($progress)); + } - # ping scan. - else { - my @hosts = map { (split('/', $_))[0] } $net_addr->hostenum; - next if (scalar(@hosts) == 0); + # Update progress. + $self->call('message', "Searching for hosts (".$total_hosts." / ".$total_hosts.")", 5); + $progress = ceil($progress); + $self->{'c_network_percent'} = 50; - $self->{'summary'}->{'discovered'} += scalar(@hosts); + # Populate. + $self->call('update_progress', ceil($progress)); - my $step = 50.0 / scalar(@subnets) / scalar(@hosts); # The first 50% of the recon task approx. - my $subnet_step = 100.0 / scalar(@hosts); - foreach my $host (@hosts) { + $total_hosts = scalar keys %hosts_alive; + if ($total_hosts == 0) { + # Populate. + $self->{'c_network_percent'} += 50; + $self->call('update_progress', ceil($progress)+25); + next; + } + $step = 25.0 / scalar(@subnets) / $total_hosts; + $subnet_step = 50.0 / $total_hosts; - $self->call('message', "Scanning host: $host", 5); - $self->call('update_progress', ceil($progress)); - $progress += $step; + $self->{'step'} = STEP_CAPABILITIES; + foreach my $addr (keys %hosts_alive) { + # Increase self summary.alive hosts. + $self->call('message', "Scanning host: $addr", 5); + $self->{'c_network_name'} = $addr; - # Check if the host is up. - if ($self->ping($host) == 0) { - $self->{'summary'}->{'not_alive'} += 1; - next; - } + # Update progress. + $progress += $step; + $self->{'c_network_percent'} += $subnet_step; - $self->{'summary'}->{'alive'} += 1; - $self->{'c_network_percent'} += $subnet_step; + # Populate. + $self->call('update_progress', ceil($progress)); - $self->snmp_discovery($host); - - # Add wmi scan if enabled. - $self->wmi_scan($host) if ($self->{'wmi_enabled'} == 1); - } - } - } + # Enable/ disable capabilities. + $self->test_capabilities($addr); + } + } } - -########################################################################## +################################################################################ # Perform a Cloud scan -########################################################################## +################################################################################ sub cloud_scan($) { - my $self = shift; - my ($progress, $step); + my $self = shift; + my ($progress, $step); - my $type = ''; + my $type = ''; - if ( $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2 - || $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { - $type = 'Aws'; - } else { + if ( $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_EC2 + || $self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { + $type = 'Aws'; + } else { - # Unrecognized task type. - $self->call('message', 'Unrecognized task type', 1); - $self->call('update_progress', -1); - return; - } + # Unrecognized task type. + $self->call('message', 'Unrecognized task type', 1); + $self->call('update_progress', -1); + return; + } - # Initialize cloud object. - my $cloudObj = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Cloud::'.$type, - [ - task_data => $self->{'task_data'}, - aws_access_key_id => $self->{'aws_access_key_id'}, - aws_secret_access_key => $self->{'aws_secret_access_key'}, - cloud_util_path => $self->{'cloud_util_path'}, - creds_file => $self->{'creds_file'}, - parent => $self - ] + # Initialize cloud object. + my $cloudObj = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Cloud::'.$type, + [ + task_data => $self->{'task_data'}, + aws_access_key_id => $self->{'aws_access_key_id'}, + aws_secret_access_key => $self->{'aws_secret_access_key'}, + cloud_util_path => $self->{'cloud_util_path'}, + creds_file => $self->{'creds_file'}, + parent => $self + ] - ); + ); - if (!$cloudObj) { + if (!$cloudObj) { - # Failed to initialize, check Cloud credentials or anything. - $self->call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3); - } else { + # Failed to initialize, check Cloud credentials or anything. + $self->call('message', 'Unable to initialize PandoraFMS::Recon::Cloud::'.$type, 3); + } else { - # Let Cloud object manage scan. - $cloudObj->scan(); - } + # Let Cloud object manage scan. + $cloudObj->scan(); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } -########################################################################## +################################################################################ # Performs a database scan. -########################################################################## +################################################################################ sub database_scan($$$) { - my ($self, $type, $obj, $global_percent, $targets) = @_; + my ($self, $type, $obj, $global_percent, $targets) = @_; - my @data; - my @modules; + my @data; + my @modules; - my $dbObjCfg = $obj->get_config(); + my $dbObjCfg = $obj->get_config(); - $self->{'summary'}->{'discovered'} += 1; - $self->{'summary'}->{'alive'} += 1; + $self->{'summary'}->{'discovered'} += 1; + $self->{'summary'}->{'alive'} += 1; - push @modules, - { - name => $type . ' connection', - type => 'generic_proc', - data => 1, - description => $type . ' availability' - }; + push @modules, + { + name => $type . ' connection', + type => 'generic_proc', + data => 1, + description => $type . ' availability' + }; - # Analyze. - $self->{'step'} = STEP_STATISTICS; - $self->{'c_network_percent'} = 30; - $self->call('update_progress', $global_percent + (30 / (scalar @$targets))); - $self->{'c_network_name'} = $obj->get_host(); + # Analyze. + $self->{'step'} = STEP_STATISTICS; + $self->{'c_network_percent'} = 30; + $self->call('update_progress', $global_percent + (30 / (scalar @$targets))); + $self->{'c_network_name'} = $obj->get_host(); - # Retrieve connection statistics. - # Retrieve uptime statistics - # Retrieve query stats - # Retrieve connections - # Retrieve innodb - # Retrieve cache - $self->{'c_network_percent'} = 50; - $self->call('update_progress', $global_percent + (50 / (scalar @$targets))); - push @modules, $obj->get_statistics(); + # Retrieve connection statistics. + # Retrieve uptime statistics + # Retrieve query stats + # Retrieve connections + # Retrieve innodb + # Retrieve cache + $self->{'c_network_percent'} = 50; + $self->call('update_progress', $global_percent + (50 / (scalar @$targets))); + push @modules, $obj->get_statistics(); - # Custom queries. - $self->{'step'} = STEP_CUSTOM_QUERIES; - $self->{'c_network_percent'} = 80; - $self->call('update_progress', $global_percent + (80 / (scalar @$targets))); - push @modules, $obj->execute_custom_queries(); + # Custom queries. + $self->{'step'} = STEP_CUSTOM_QUERIES; + $self->{'c_network_percent'} = 80; + $self->call('update_progress', $global_percent + (80 / (scalar @$targets))); + push @modules, $obj->execute_custom_queries(); - if (defined($dbObjCfg->{'scan_databases'}) - && "$dbObjCfg->{'scan_databases'}" eq "1") { + if (defined($dbObjCfg->{'scan_databases'}) + && "$dbObjCfg->{'scan_databases'}" eq "1") { - # Skip database scan in Oracle tasks - next if defined($self->{'type'}) && $self->{'type'} == DISCOVERY_APP_ORACLE; + # Skip database scan in Oracle tasks + next if defined($self->{'type'}) && $self->{'type'} == DISCOVERY_APP_ORACLE; - my $__data = $obj->scan_databases(); + my $__data = $obj->scan_databases(); - if (ref($__data) eq "ARRAY") { - if (defined($dbObjCfg->{'agent_per_database'}) - && $dbObjCfg->{'agent_per_database'} == 1) { + if (ref($__data) eq "ARRAY") { + if (defined($dbObjCfg->{'agent_per_database'}) + && $dbObjCfg->{'agent_per_database'} == 1) { - # Agent per database detected. - push @data, @{$__data}; + # Agent per database detected. + push @data, @{$__data}; - } else { + } else { - # Merge modules into engine agent. - my @_modules = map { - map { $_ } - @{$_->{'module_data'}} - } @{$__data}; + # Merge modules into engine agent. + my @_modules = map { + map { $_ } + @{$_->{'module_data'}} + } @{$__data}; - push @modules, @_modules; - } - } - } + push @modules, @_modules; + } + } + } - return { - 'modules' => \@modules, - 'data' => \@data - }; + return { + 'modules' => \@modules, + 'data' => \@data + }; } -########################################################################## +################################################################################ # Perform an Application scan. -########################################################################## +################################################################################ sub app_scan($) { - my ($self) = @_; - my ($progress, $step); + my ($self) = @_; + my ($progress, $step); - my $type = ''; - my $db_scan = 0; + my $type = ''; + my $db_scan = 0; - # APP object initialization. - if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) { - $type = 'MySQL'; - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { - $type = 'Oracle'; - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - $type = 'SAP'; - } else { - # Unrecognized task type. - $self->call('message', 'Unrecognized task type', 1); - $self->call('update_progress', -1); - return; - } + # APP object initialization. + if ($self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL) { + $type = 'MySQL'; + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { + $type = 'Oracle'; + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + $type = 'SAP'; + } else { + # Unrecognized task type. + $self->call('message', 'Unrecognized task type', 1); + $self->call('update_progress', -1); + return; + } - my @targets = split /,/, $self->{'task_data'}->{'subnet'}; + my @targets = split /,/, $self->{'task_data'}->{'subnet'}; - my $global_step = 100 / (scalar @targets); - my $global_percent = 0; - my $i = 0; - foreach my $target (@targets) { - if ( !defined($target) - || $target eq '' - || $target =~ /^#/) { - # Ignore empty target or commented one. - next; - } + my $global_step = 100 / (scalar @targets); + my $global_percent = 0; + my $i = 0; + foreach my $target (@targets) { + if ( !defined($target) + || $target eq '' + || $target =~ /^#/) { + # Ignore empty target or commented one. + next; + } - my @data; - my @modules; + my @data; + my @modules; - $self->{'step'} = STEP_APP_SCAN; - $self->{'c_network_name'} = $target; - $self->{'c_network_percent'} = 0; + $self->{'step'} = STEP_APP_SCAN; + $self->{'c_network_name'} = $target; + $self->{'c_network_percent'} = 0; - # Send message - $self->call('message', 'Checking target ' . $target, 10); + # Send message + $self->call('message', 'Checking target ' . $target, 10); - # Force target acquirement. - $self->{'task_data'}->{'dbhost'} = $target; - $self->{'task_data'}->{'target_index'} = $i++; + # Force target acquirement. + $self->{'task_data'}->{'dbhost'} = $target; + $self->{'task_data'}->{'target_index'} = $i++; - # Update progress - $self->{'c_network_percent'} = 10; - $self->call('update_progress', $global_percent + (10 / (scalar @targets))); + # Update progress + $self->{'c_network_percent'} = 10; + $self->call('update_progress', $global_percent + (10 / (scalar @targets))); - # Connect to target. - my $obj = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Applications::'.$type, - { - %{$self->{'task_data'}}, - 'target' => $target, - 'pa_config' => $self->{'pa_config'}, - 'parent' => $self - }, - ); + # Connect to target. + my $obj = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Applications::'.$type, + { + %{$self->{'task_data'}}, + 'target' => $target, + 'pa_config' => $self->{'pa_config'}, + 'parent' => $self + }, + ); - if (defined($obj)) { + if (defined($obj)) { - # Verify if object is connected. If cannot connect to current target - # return with module. - if (!$obj->is_connected()) { - $self->call('message', 'Cannot connect to target ' . $target, 3); - $global_percent += $global_step; - $self->{'c_network_percent'} = 90; + # Verify if object is connected. If cannot connect to current target + # return with module. + if (!$obj->is_connected()) { + $self->call('message', 'Cannot connect to target ' . $target, 3); + $global_percent += $global_step; + $self->{'c_network_percent'} = 90; - # Update progress - $self->call('update_progress', $global_percent + (90 / (scalar @targets))); - $self->{'summary'}->{'not_alive'} += 1; - push @modules, { - name => $type . ' connection', - type => 'generic_proc', - data => 0, - description => $type . ' availability' - }; + # Update progress + $self->call('update_progress', $global_percent + (90 / (scalar @targets))); + $self->{'summary'}->{'not_alive'} += 1; + push @modules, { + name => $type . ' connection', + type => 'generic_proc', + data => 0, + description => $type . ' availability' + }; - } else { - # - # $results is always a hash with: - # @modules => 'global' modules. - # @data => { - # 'agent_data' => {} - # 'module_data' => [] - # } - my $results; + } else { + # + # $results is always a hash with: + # @modules => 'global' modules. + # @data => { + # 'agent_data' => {} + # 'module_data' => [] + # } + my $results; - # Scan connected obj. - if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { + # Scan connected obj. + if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE) { - # Database. - $results = $self->database_scan($type, $obj, $global_percent, \@targets); + # Database. + $results = $self->database_scan($type, $obj, $global_percent, \@targets); - } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + } elsif ($self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - # SAP scan - $results = $obj->scan(); + # SAP scan + $results = $obj->scan(); - } + } - # Add results. - if (ref($results) eq 'HASH') { - if (defined($results->{'modules'})) { - push @modules, @{$results->{'modules'}}; - } + # Add results. + if (ref($results) eq 'HASH') { + if (defined($results->{'modules'})) { + push @modules, @{$results->{'modules'}}; + } - if (defined($results->{'data'})) { - push @data, @{$results->{'data'}}; - } - } - } + if (defined($results->{'data'})) { + push @data, @{$results->{'data'}}; + } + } + } - # Put engine agent at the beginning of the list. - my $version = $obj->get_version(); - unshift @data, { - 'agent_data' => { - 'agent_name' => $obj->get_agent_name(), - 'os' => $type, - 'os_version' => (defined($version) ? $version : 'Discovery'), - 'interval' => $self->{'task_data'}->{'interval_sweep'}, - 'id_group' => $self->{'task_data'}->{'id_group'}, - 'address' => $obj->get_host(), - 'description' => '', - }, - 'module_data' => \@modules, - }; + # Put engine agent at the beginning of the list. + my $version = $obj->get_version(); + unshift @data, { + 'agent_data' => { + 'agent_name' => $obj->get_agent_name(), + 'os' => $type, + 'os_version' => (defined($version) ? $version : 'Discovery'), + 'interval' => $self->{'task_data'}->{'interval_sweep'}, + 'id_group' => $self->{'task_data'}->{'id_group'}, + 'address' => $obj->get_host(), + 'description' => '', + }, + 'module_data' => \@modules, + }; - $self->call('create_agents', \@data); + $self->call('create_agents', \@data); - # Destroy item. - undef($obj); - } + # Destroy item. + undef($obj); + } - $global_percent += $global_step; - $self->{'c_network_percent'} = 100; - $self->call('update_progress', $global_percent); - } + $global_percent += $global_step; + $self->{'c_network_percent'} = 100; + $self->call('update_progress', $global_percent); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } -########################################################################## +################################################################################ # Perform a deployment scan. -########################################################################## +################################################################################ sub deploy_scan($) { - my $self = shift; - my ($progress, $step); + my $self = shift; + my ($progress, $step); - my $type = ''; + my $type = ''; - # Initialize deployer object. - my $deployer = PandoraFMS::Recon::Util::enterprise_new( - 'PandoraFMS::Recon::Deployer', - [ - task_data => $self->{'task_data'}, - parent => $self - ] + # Initialize deployer object. + my $deployer = PandoraFMS::Recon::Util::enterprise_new( + 'PandoraFMS::Recon::Deployer', + [ + task_data => $self->{'task_data'}, + parent => $self + ] - ); + ); - if (!$deployer) { + if (!$deployer) { - # Failed to initialize, check Cloud credentials or anything. - $self->call('message', 'Unable to initialize PandoraFMS::Recon::Deployer', 3); - } else { + # Failed to initialize, check Cloud credentials or anything. + $self->call('message', 'Unable to initialize PandoraFMS::Recon::Deployer', 3); + } else { - # Let deployer object manage scan. - $deployer->scan(); - } + # Let deployer object manage scan. + $deployer->scan(); + } - # Update progress. - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Update progress. + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); } -########################################################################## +################################################################################ # Perform a network scan. -########################################################################## +################################################################################ sub scan($) { - my ($self) = @_; - my ($progress, $step) = 1, 0; + my ($self) = @_; + my ($progress, $step) = 1, 0; - # 1% - $self->call('update_progress', 1); + # 1% + $self->call('update_progress', 1); - if (defined($self->{'task_data'})) { - if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE - || $self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { - # Application scan. - $self->call('message', "Scanning application ...", 6); - return $self->app_scan(); - } + if (defined($self->{'task_data'})) { + if ( $self->{'task_data'}->{'type'} == DISCOVERY_APP_MYSQL + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_ORACLE + || $self->{'task_data'}->{'type'} == DISCOVERY_APP_SAP) { + # Application scan. + $self->call('message', "Scanning application ...", 6); + return $self->app_scan(); + } - if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { + if ($self->{'task_data'}->{'type'} == DISCOVERY_CLOUD_AWS_RDS) { - # Cloud scan. - return $self->cloud_scan(); - } + # Cloud scan. + return $self->cloud_scan(); + } - if($self->{'task_data'}->{'type'} == DISCOVERY_DEPLOY_AGENTS) { - return $self->deploy_scan(); - } - } + if($self->{'task_data'}->{'type'} == DISCOVERY_DEPLOY_AGENTS) { + return $self->deploy_scan(); + } + } - # Find devices. - $self->call('message', "[1/4] Scanning the network...", 3); - $self->{'step'} = STEP_SCANNING; - $self->call('update_progress', $progress); - $self->scan_subnet(); + if(defined($self->{'task_data'}{'review_mode'}) + && $self->{'task_data'}{'review_mode'} == DISCOVERY_RESULTS + ) { + # Use Cached results. + $self->{'step'} = STEP_PROCESSING; + $self->call('report_scanned_agents'); - # Read the local ARP cache. - $self->local_arp(); + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); + return; + } - # Get a list of found hosts. - my @hosts = @{$self->get_hosts()}; - if (scalar(@hosts) > 0 && $self->{'parent_detection'} == 1) { + # Find devices. + $self->call('message', "[1/6] Scanning the network...", 3); + $self->{'c_network_name'} = ''; + $self->{'step'} = STEP_SCANNING; + $self->call('update_progress', $progress); - # Delete previous connections. - $self->call('delete_connections'); + $self->scan_subnet(); + # Read the local ARP cache. + $self->local_arp(); - # Connectivity from address forwarding tables. - $self->call('message', "[2/4] Finding address forwarding table connectivity...", 3); - $self->{'step'} = STEP_AFT; - ($progress, $step) = (50, 20.0 / scalar(@hosts)); # From 50% to 70%. - for (my $i = 0; defined($hosts[$i]); $i++) { - $self->call('update_progress', $progress); - $progress += $step; - $self->aft_connectivity($hosts[$i]); - } + # Get a list of found hosts. + my @hosts = @{$self->get_hosts()}; + if (scalar(@hosts) > 0 && $self->{'parent_detection'} == 1) { - # Connect hosts that are still unconnected using traceroute. - $self->call('message', "[3/4] Finding traceroute connectivity.", 3); - $self->{'step'} = STEP_TRACEROUTE; - ($progress, $step) = (70, 20.0 / scalar(@hosts)); # From 70% to 90%. - foreach my $host (@hosts) { - $self->call('update_progress', $progress); - $progress += $step; - next if ($self->has_parent($host) || $self->has_children($host)); - $self->traceroute_connectivity($host); - } + # Delete previous connections. + $self->call('delete_connections'); - # Connect hosts that are still unconnected using known gateways. - $self->call('message', "[4/4] Finding host to gateway connectivity.", 3); - $self->{'step'} = STEP_GATEWAY; - ($progress, $step) = (90, 10.0 / scalar(@hosts)); # From 70% to 90%. - $self->get_routes(); # Update the route cache. - foreach my $host (@hosts) { - $self->call('update_progress', $progress); - $progress += $step; - next if ($self->has_parent($host)); - $self->gateway_connectivity($host); - } - } + # Connectivity from address forwarding tables. + $self->call('message', "[2/6] Finding address forwarding table connectivity...", 3); + $self->{'c_network_name'} = ''; + $self->{'step'} = STEP_AFT; + ($progress, $step) = (50, 10.0 / scalar(@hosts)); # From 50% to 60%. + for (my $i = 0; defined($hosts[$i]); $i++) { + $self->call('update_progress', $progress); + $progress += $step; + $self->aft_connectivity($hosts[$i]); + } - # Done! - $self->{'step'} = ''; - $self->call('update_progress', -1); + # Connect hosts that are still unconnected using traceroute. + $self->call('message', "[3/6] Finding traceroute connectivity.", 3); + $self->{'c_network_name'} = ''; + $self->{'step'} = STEP_TRACEROUTE; + ($progress, $step) = (60, 10.0 / scalar(@hosts)); # From 60% to 70%. + foreach my $host (@hosts) { + $self->call('update_progress', $progress); + $progress += $step; + next if ($self->has_parent($host) || $self->has_children($host)); + $self->traceroute_connectivity($host); + } - # Print debug information on found devices. - $self->call('message', "[Summary]", 3); - foreach my $host (@hosts) { - my $device = $self->get_device($host); - next unless defined($device); + # Connect hosts that are still unconnected using known gateways. + $self->call('message', "[4/6] Finding host to gateway connectivity.", 3); + $self->{'c_network_name'} = ''; + $self->{'step'} = STEP_GATEWAY; + ($progress, $step) = (70, 10.0 / scalar(@hosts)); # From 70% to 80%. + $self->get_routes(); # Update the route cache. + foreach my $host (@hosts) { + $self->call('update_progress', $progress); + $progress += $step; + next if ($self->has_parent($host)); + $self->gateway_connectivity($host); + } + } + + # Apply monitoring templates + $self->call('message', "[5/6] Applying monitoring.", 3); + $self->{'step'} = STEP_MONITORING; + $self->call('apply_monitoring', $self); + + # Print debug information on found devices. + $self->call('message', "[Summary]", 3); + foreach my $host (@hosts) { + my $device = $self->get_device($host); + next unless defined($device); + + # Print device information. + my $dev_info = "Device: " . $device->{'type'} . " ("; + foreach my $ip_address ($self->get_addresses($host)) { + $dev_info .= "$ip_address,"; + } + chop($dev_info); + $dev_info .= ')'; + $self->call('message', $dev_info, 3); + } + + # Apply monitoring templates + $self->call('message', "[6/6] Processing results.", 3); + $self->{'step'} = STEP_PROCESSING; + # Send agent information to Database (Discovery) or XML (satellite.). + $self->call('report_scanned_agents'); + + if(defined($self->{'task_data'}{'review_mode'}) + && $self->{'task_data'}{'review_mode'} == DISCOVERY_STANDARD + ) { + # Send agent information to Database (Discovery) or XML (satellite.). + $self->call('report_scanned_agents', 1); + } + + # Done! + $self->{'step'} = ''; + $self->call('update_progress', -1); - # Print device information. - my $dev_info = "Device: " . $device->{'type'} . " ("; - foreach my $ip_address ($self->get_addresses($host)) { - $dev_info .= "$ip_address,"; - } - chop($dev_info); - $dev_info .= ')'; - $self->call('message', $dev_info, 3); - } } -######################################################################################## +################################################################################ # Set an SNMP community for the given device. -######################################################################################## +################################################################################ sub set_community($$$) { - my ($self, $device, $community) = @_; + my ($self, $device, $community) = @_; - $self->{'community_cache'}->{$device} = $community; + $self->{'community_cache'}->{$device} = $community; } -######################################################################################## +################################################################################ # Set the type of the given device. -######################################################################################## +################################################################################ sub set_device_type($$$) { - my ($self, $device, $type) = @_; + my ($self, $device, $type) = @_; - $self->{'visited_devices'}->{$device}->{'type'} = $type; + $self->{'visited_devices'}->{$device}->{'type'} = $type; } -######################################################################################## +################################################################################ +# Calculate +################################################################################ +sub snmp_pen($$) { + my ($self, $addr) = @_; + + $self->{'pen'} = {} if ref($self->{'pen'}) ne 'HASH'; + + $self->{'pen'}{$addr} = $self->snmp_get_value($addr, $PEN_OID); + + if(defined($self->{'pen'}{$addr})) { + ($self->{'pen'}{$addr}) = $self->{'pen'}{$addr} =~ /\.\d+\.\d+\.\d+\.\d+\.\d+\.\d+\.(\d+?)\./ + } + +} + +################################################################################ # Performs an SNMP WALK and returns the response as an array. -######################################################################################## +################################################################################ sub snmp_get($$$) { - my ($self, $device, $oid) = @_; - my @output; + my ($self, $device, $oid) = @_; + my @output; - return () unless defined $self->is_snmp_discovered($device); - my $community = $self->get_community($device); + return () unless defined $self->is_snmp_discovered($device); + my $community = $self->get_community($device); - # Check the SNMP query cache first. - if (defined($self->{'snmp_cache'}->{"${device}_${oid}"})) { - return @{$self->{'snmp_cache'}->{"${device}_${oid}"}}; - } + # Check the SNMP query cache first. + if (defined($self->{'snmp_cache'}->{"${device}_${oid}"})) { + return @{$self->{'snmp_cache'}->{"${device}_${oid}"}}; + } - # Check VLANS. - my @vlans = $self->get_vlans($device); - if (scalar(@vlans) == 0) { - my $command = $self->snmp_get_command($device, $oid, $community); - @output = `$command`; - }else { + # Check VLANS. + my @vlans = $self->get_vlans($device); + if (scalar(@vlans) == 0) { + my $command = $self->snmp_get_command($device, $oid, $community); + @output = `$command`; + }else { - # Handle duplicate lines. - my %output_hash; - foreach my $vlan (@vlans) { - my $command = $self->snmp_get_command($device, $oid, $community, $vlan); - foreach my $line (`$command`) { - $output_hash{$line} = 1; - } - } - push(@output, keys(%output_hash)); - } + # Handle duplicate lines. + my %output_hash; + foreach my $vlan (@vlans) { + my $command = $self->snmp_get_command($device, $oid, $community, $vlan); + foreach my $line (`$command`) { + $output_hash{$line} = 1; + } + } + push(@output, keys(%output_hash)); + } - # Update the SNMP query cache. - $self->{'snmp_cache'}->{"${device}_${oid}"} = [@output]; + # Update the SNMP query cache. + $self->{'snmp_cache'}->{"${device}_${oid}"} = [@output]; - return @output; + return @output; } -######################################################################################## +################################################################################ # Get the snmpwalk command seing version 1, 2, 2c or 3. -######################################################################################## +################################################################################ sub snmp_get_command { - my ($self, $device, $oid, $community, $vlan) = @_; - $vlan = defined($vlan) ? "\@" . $vlan : ''; + my ($self, $device, $oid, $community, $vlan) = @_; + $vlan = defined($vlan) ? "\@" . $vlan : ''; - my $command = "snmpwalk -M$DEVNULL -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; - if ($self->{'snmp_version'} eq "3") { - if ($self->{'community'}) { # Context - $command .= " -N $self->{'community'} "; - } - $command .= " -l$self->{'snmp_security_level'} "; - if ($self->{'snmp_security_level'} ne "noAuthNoPriv") { - $command .= " -u$self->{'snmp_auth_user'} -a$self->{'snmp_auth_method'} -A$self->{'snmp_auth_pass'} "; - } - if ($self->{'snmp_security_level'} eq "authPriv") { - $command .= " -x$self->{'snmp_privacy_method'} -X$self->{'snmp_privacy_pass'} "; - } - } else { - $command .= " -c$community$vlan "; - } + my $command = "snmpwalk -M$DEVNULL -r$self->{'snmp_checks'} -t$self->{'snmp_timeout'} -v$self->{'snmp_version'} -On -Oe "; + if ($self->{'snmp_version'} eq "3") { + if ($self->{'community'}) { # Context + $command .= " -N $self->{'community'} "; + } + $command .= " -l$self->{'snmp_security_level'} "; + if ($self->{'snmp_security_level'} ne "noAuthNoPriv") { + $command .= " -u$self->{'snmp_auth_user'} -a$self->{'snmp_auth_method'} -A$self->{'snmp_auth_pass'} "; + } + if ($self->{'snmp_security_level'} eq "authPriv") { + $command .= " -x$self->{'snmp_privacy_method'} -X$self->{'snmp_privacy_pass'} "; + } + } else { + $command .= " -c$community$vlan "; + } - return "$command $device $oid 2>$DEVNULL"; + return "$command $device $oid 2>$DEVNULL"; } -######################################################################################## +################################################################################ # Performs an SNMP WALK and returns the value of the given OID. Returns undef # on error. -######################################################################################## +################################################################################ sub snmp_get_value($$$) { - my ($self, $device, $oid) = @_; + my ($self, $device, $oid) = @_; - my @output = $self->snmp_get($device, $oid); - foreach my $line (@output) { - chomp($line); - return $1 if ($line =~ /^$oid\s+=\s+\S+:\s+(.*)$/); - } + my $effective_oid = $oid; + if (is_enabled($self->{'translate_snmp'})) { + $effective_oid = `snmptranslate $oid -On 2>$DEVNULL`; + chomp($effective_oid); + } - return undef; + my @output = $self->snmp_get($device, $effective_oid); + + foreach my $line (@output) { + chomp($line); + return $1 if ($line =~ /^$effective_oid\s+=\s+\S+:\s+(.*)$/); + } + + return undef; } -######################################################################################## +################################################################################ # Performs an SNMP WALK and returns an array of values. -######################################################################################## +################################################################################ sub snmp_get_value_array($$$) { - my ($self, $device, $oid) = @_; - my @values; + my ($self, $device, $oid) = @_; + my @values; - my @output = $self->snmp_get($device, $oid); - foreach my $line (@output) { - chomp($line); - push(@values, $1) if ($line =~ /^$oid\S*\s+=\s+\S+:\s+(.*)$/); - } + my @output = $self->snmp_get($device, $oid); + foreach my $line (@output) { + chomp($line); + push(@values, $1) if ($line =~ /^$oid\S*\s+=\s+\S+:\s+(.*)$/); + } - return @values; + return @values; } -######################################################################################## +################################################################################ # Performs an SNMP WALK and returns a hash of values. -######################################################################################## +################################################################################ sub snmp_get_value_hash($$$) { - my ($self, $device, $oid) = @_; - my %values; + my ($self, $device, $oid) = @_; + my %values; - my @output = $self->snmp_get_value_array($device, $oid); - foreach my $line (@output) { - $values{$line} = ''; - } + my @output = $self->snmp_get_value_array($device, $oid); + foreach my $line (@output) { + $values{$line} = ''; + } - return %values; + return %values; } -########################################################################## +################################################################################ # Connect the given host to its parent using traceroute. -########################################################################## +################################################################################ sub traceroute_connectivity($$) { - my ($self, $host) = @_; + my ($self, $host) = @_; - # Perform a traceroute. - my $nmap_args = '-nsP -PE --traceroute --max-retries '.$self->{'icmp_checks'}.' --host-timeout '.$self->{'icmp_timeout'}.'s -T'.$self->{'recon_timing_template'}; - my $np = PandoraFMS::Recon::NmapParser->new(); - eval {$np->parsescan($self->{'nmap'}, $nmap_args, ($host));}; - return if ($@); + # Perform a traceroute. + my $nmap_args = '-nsP -PE --traceroute --max-retries '.$self->{'icmp_checks'}.' --host-timeout '.$self->{'icmp_timeout'}.'s -T'.$self->{'recon_timing_template'}; + my $np = PandoraFMS::Recon::NmapParser->new(); + eval {$np->parsescan($self->{'nmap'}, $nmap_args, ($host));}; + return if ($@); - # Get hops to the host. - my ($h) = $np->all_hosts(); - return unless defined($h); - my @hops = $h->all_trace_hops(); + # Get hops to the host. + my ($h) = $np->all_hosts(); + return unless defined($h); + my @hops = $h->all_trace_hops(); - # Skip the target host. - pop(@hops); + # Skip the target host. + pop(@hops); - # Reverse the host order (closest hosts first). - @hops = reverse(@hops); + # Reverse the host order (closest hosts first). + @hops = reverse(@hops); - # Look for parents. - my $device = $host; - for (my $i = 0; $i < $self->{'parent_recursion'}; $i++) { - next unless defined($hops[$i]); - my $parent = $hops[$i]->ipaddr(); + # Look for parents. + my $device = $host; + for (my $i = 0; $i < $self->{'parent_recursion'}; $i++) { + next if is_empty($hops[$i]); + my $parent = $hops[$i]->ipaddr(); - # Create an agent for the parent. - $self->call('create_agent', $parent); + # Create an agent for the parent. + $self->add_agent($parent); - $self->call('message', "Host $device is one hop away from host $parent.", 5); - $self->mark_connected($parent, '', $device, ''); + $self->call('message', "Host $device is one hop away from host $parent.", 5); + $self->mark_connected($parent, '', $device, ''); - # Move on to the next hop. - $device = $parent; - } + # Move on to the next hop. + $device = $parent; + } } -########################################################################## +################################################################################ # Returns the credentials with which the host responds to WMI queries or # undef if it does not respond to WMI. -########################################################################## -sub responds_to_wmi { - 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`; - } - - foreach my $line (@output) { - chomp($line); - return $auth if ($line =~ m/^CLASS: Win32_ComputerSystem$/); - } - } - - return undef; +################################################################################ +sub wmi_credentials { + my ($self, $target) = @_; + return $self->{'wmi_auth'}{$target}; } -########################################################################## -# Add wmi modules to the given host. -########################################################################## -sub wmi_scan { +################################################################################ +# Returns the credentials KEY with which the host responds to WMI queries or +# undef if it does not respond to WMI. +################################################################################ +sub wmi_credentials_key { my ($self, $target) = @_; - - $self->call('message', "[".$target."] Checking WMI.", 5); - - my $auth = $self->responds_to_wmi($target); - return unless defined($auth); - - $self->{'summary'}->{'WMI'} += 1; - - $self->call('message', "[".$target."] WMI available.", 10); - - # Create the agent if it does not exist. - my $agent_id = $self->call('create_agent', $target); - next unless defined($agent_id); - - # CPU. - my @cpus = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceId FROM Win32_Processor', 0); - foreach my $cpu (@cpus) { - $self->call('wmi_module',($agent_id,$target,"SELECT LoadPercentage FROM Win32_Processor WHERE DeviceId='$cpu'",$auth,1,"CPU Load $cpu","Load for $cpu (%)",'generic_data')); - } - - # Memory. - my $mem = $self->wmi_get_value($target, $auth, 'SELECT FreePhysicalMemory FROM Win32_OperatingSystem', 0); - if (defined($mem)) { - $self->call('wmi_module',($agent_id,$target,"SELECT FreePhysicalMemory, TotalVisibleMemorySize FROM Win32_OperatingSystem",$auth,0,'FreeMemory','Free memory','generic_data','KB')); - } - - # Disk. - my @units = $self->wmi_get_value_array($target, $auth, 'SELECT DeviceID FROM Win32_LogicalDisk', 0); - foreach my $unit (@units) { - $self->call('wmi_module',($agent_id,$target,"SELECT FreeSpace FROM Win32_LogicalDisk WHERE DeviceID='$unit'",$auth,1,"FreeDisk $unit",'Available disk space in kilobytes','generic_data','KB')); - } + return $self->{'wmi_auth_key'}{$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) = @_; + + # Test empty credentials. + my @output = `$self->{'timeout_cmd'}$self->{'wmi_client'} -N //$target "SELECT * FROM Win32_ComputerSystem" 2>$DEVNULL`; + my $rs = $self->wmi_output_check($?, @output); + + if ($rs == WMI_OK) { + $self->{'wmi_auth'}{$target} = ''; + $self->{'wmi_auth_key'}{$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>$DEVNULL`; + + my $rs = $self->wmi_output_check($?, @output); + + if ($rs == WMI_OK) { + $self->{'wmi_auth'}{$target} = $auth; + $self->{'wmi_auth_key'}{$target} = $key_index; + $self->{'wmi'}{$target} = 1; + $self->{'summary'}->{'WMI'} += 1; + $self->call('message', "[".$target."] WMI available.", 10); + return 1; + } + + if ($rs == WMI_UNREACHABLE) { + # Target does not respond. + $self->call('message', "[".$target."] WMI unreachable.", 10); + $self->{'wmi'}{$target} = 0; + return undef; + } + } + + return undef; +} + +################################################################################ +# Tests wmi capability for addr. +################################################################################ +sub wmi_discovery { + my ($self, $addr) = @_; + + # Initialization. + $self->{'wmi'} = {} unless ref($self->{'wmi'}) eq 'HASH'; + + # Calculate credentials. + $self->wmi_credentials_calculation($addr); + +} + +################################################################################ # Extra: WMI imported methods. DO NOT EXPORT TO AVOID DOUBLE DEF. -########################################################################## +################################################################################ -########################################################################## -# Performs a wmi get requests and returns the response as an array. -########################################################################## -sub wmi_get { - my ($self, $target, $auth, $query) = @_; +################################################################################ +# 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; - my @output; - if (defined($auth) && $auth ne '') { - @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -U $auth //$target "$query" 2>&1`; - }else { - @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -N //$target "$query" 2>&1`; - } + if ($err =~ /NT_STATUS_IO_TIMEOUT/ + || $err =~ /NT_STATUS_CONNECTION_REFUSED/ + ) { + # Fail. + return WMI_UNREACHABLE; + } - # Something went wrong. - return () if ($? != 0); + if ($err =~ /NT_STATUS_ACCESS_DENIED/) { + return WMI_BAD_PASSWORD; + } + } - return @output; + # 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) = @_; + + return () if is_empty($target); + + my @output; + if (defined($auth) && $auth ne '') { + $auth =~ s/'/\'/g; + @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -U '$auth' //$target "$query" 2>$DEVNULL`; + }else { + @output = `$self->{'timeout_cmd'}"$self->{'wmi_client'}" -N //$target "$query" 2>$DEVNULL`; + } + + my $rs = $self->wmi_output_check($?, @output); + + if ($rs == WMI_OK) { + return @output; + } + + my $err = $self->{'last_wmi_error'}; + $err = 'Not OK, empty error' if is_empty($err); + + $self->call( + 'message', + "[".$target."] WMI error: ".$err, + 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; +} + +################################################################################ # Performs a WMI request and returns the requested column of the first row. # Returns undef on error. -########################################################################## +################################################################################ sub wmi_get_value { - my ($self, $target, $auth, $query, $column) = @_; - my @result; + my ($self, $target, $query, $column) = @_; + my @result; - my @output = $self->wmi_get($target, $auth, $query); - return undef unless defined($output[2]); + my @output = $self->wmi_get($target, $query); + return undef unless defined($output[2]); - my $line = $output[2]; - chomp($line); - my @columns = split(/\|/, $line); - return undef unless defined($columns[$column]); + my $line = $output[2]; + chomp($line); + my @columns = split(/\|/, $line); + return undef unless defined($columns[$column]); - return $columns[$column]; + return $columns[$column]; } -########################################################################## +################################################################################ # Performs a WMI request and returns row values for the requested column # in an array. -########################################################################## +################################################################################ sub wmi_get_value_array { - my ($self, $target, $auth, $query, $column) = @_; - my @result; + my ($self, $target, $query, $column) = @_; + my @result; - my @output = $self->wmi_get($target, $auth, $query); - foreach (my $i = 2; defined($output[$i]); $i++) { - my $line = $output[$i]; - chomp($line); - my @columns = split(/\|/, $line); - next unless defined($columns[$column]); - push(@result, $columns[$column]); - } + my @output = $self->wmi_get($target, $query); + foreach (my $i = 2; defined($output[$i]); $i++) { + my $line = $output[$i]; + chomp($line); + my @columns = split(/\|/, $line); + next unless defined($columns[$column]); + push(@result, $columns[$column]); + } - return @result; + return @result; } -########################################################################## +################################################################################ # END: WMI imported methods. -########################################################################## +################################################################################ 1; __END__ diff --git a/pandora_server/lib/PandoraFMS/Recon/Util.pm b/pandora_server/lib/PandoraFMS/Recon/Util.pm index 64cc7b28e6..32bc921806 100644 --- a/pandora_server/lib/PandoraFMS/Recon/Util.pm +++ b/pandora_server/lib/PandoraFMS/Recon/Util.pm @@ -23,9 +23,9 @@ our @EXPORT = qw( subnet_matches ); -######################################################################################## +################################################################################ # Return an Enterprise Recon object. -######################################################################################## +################################################################################ sub enterprise_new($$) { my ($class, $arguments) = @_; @@ -53,18 +53,18 @@ sub enterprise_new($$) { } -######################################################################################## +################################################################################ # Return the numeric representation of the given IP address. -######################################################################################## +################################################################################ sub ip_to_long($) { my $ip_address = shift; return unpack('N', inet_aton($ip_address)); } -######################################################################################## +################################################################################ # Returns 1 if the two given MAC addresses are the same. -######################################################################################## +################################################################################ sub mac_matches($$) { my ($mac_1, $mac_2) = @_; @@ -75,9 +75,9 @@ sub mac_matches($$) { return 0; } -######################################################################################## +################################################################################ # Convert a MAC address to decimal dotted notation. -######################################################################################## +################################################################################ sub mac_to_dec($) { my $mac = shift; @@ -91,9 +91,9 @@ sub mac_to_dec($) { return $dec_mac; } -######################################################################################## +################################################################################ # Make sure all MAC addresses are in the same format (00 11 22 33 44 55 66). -######################################################################################## +################################################################################ sub parse_mac($) { my ($mac) = @_; @@ -114,9 +114,9 @@ sub parse_mac($) { return $mac; } -######################################################################################## +################################################################################ # Returns 1 if the given IP address belongs to the given subnet. -######################################################################################## +################################################################################ sub subnet_matches($$;$) { my ($ipaddr, $subnet, $mask) = @_; my ($netaddr, $netmask); diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index ff6b8f1e84..11ddf8372e 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 200413 +%define release 200414 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index 719ff10fdb..cbffcc09bb 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 200413 +%define release 200414 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index 77286d428d..dd6b406114 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.744" -PI_BUILD="200413" +PI_BUILD="200414" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index a28d5e92b8..0cbbf01fb7 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 PS200413"; +my $version = "7.0NG.744 PS200414"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index 2552896724..ab784928d4 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 PS200413"; +my $version = "7.0NG.744 PS200414"; # save program name for logging my $progname = basename($0); diff --git a/pandora_server/util/plugin/wizard_snmp_module.pl b/pandora_server/util/plugin/wizard_snmp_module.pl new file mode 100755 index 0000000000..ae1d739864 --- /dev/null +++ b/pandora_server/util/plugin/wizard_snmp_module.pl @@ -0,0 +1,308 @@ +#!/usr/bin/perl +# +################################################################################ +# +# SNMP wizard module +# +# Requirements: +# Net::SNMP +# Crypt::DES +# Digest::SHA1 +# +# (c) Enrique Martin Garcia +# +# 2020/03/10 +# +################################################################################ + +use strict; +use warnings; + +use POSIX qw(strftime); + +use Encode; +use Encode::Locale; +use Getopt::Long; +use Net::SNMP; + +my $HELP=<" -version "" [SNMP] [SNMPv3] -oidList "," -operation "" + +-host Target host +-version SNMP version (1, 2c, 3) + +-oidList Comma separated OIDs used +-operation Aritmetic operation to get data. + Macros _oN_ will be changed by OIDs in list. + Example: (_o1_ * 100) / _o2_ + +[SNMP] + -community Community (only version 1 and 2c) + -port Target UDP port (Default 161) + +[SNMPv3] + -user Username + -authMethod Authentication method (MD5, SHA) + -authPass Authentication password + -privMethod Privacy method (DES, AES) + -privPass Privacy password + -secLevel Security level (noAuthNoPriv, authNoPriv, authPriv) + +Example: $0 -host 192.168.80.43 -community public -version 1 -oidlist "1.3.6.1.2.1.2.2.1.10.1,1.3.6.1.2.1.2.2.1.16.1" -operation "_o1_ + _o2_" + +EO_HELP + +# +# FUNCTIONS +############## + +sub new_snmp_target { + my ($config) = @_; + my $target; + my $error; + + if ($config->{'version'} ne '3'){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -community => $config->{'community'} + ); + }else{ + if ($config->{'sec_level'} =~ /^noAuthNoPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'} + ); + }elsif ($config->{'sec_level'} =~ /^authNoPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'}, + -authpassword => $config->{'auth_pass'}, + -authprotocol => $config->{'auth_method'} + ); + }elsif ($config->{'sec_level'} =~ /^authPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'}, + -authpassword => $config->{'auth_pass'}, + -authprotocol => $config->{'auth_method'}, + -privpassword => $config->{'priv_pass'}, + -privprotocol => $config->{'priv_method'} + ); + } + } + + + return ($target, $error); +} + +sub snmp_walk { + my ($target, $oid) = @_; + my $result = {}; + + my $walk = $target->get_table( + -baseoid => $oid, + ); + + if (defined($walk)){ + $result = $walk; + } + + return $result; +} + +sub snmp_get { + my ($target, $oid) = @_; + my $result = ''; + + my $get = $target->get_request( + -varbindlist => [$oid], + ); + + if (defined($get)){ + $result = $get->{$oid}; + } + + return $result; +} + +# +# MAIN +############## + +@ARGV = map { decode(locale => $_, 1) } @ARGV if -t STDIN; +binmode STDOUT, ":encoding(console_out)" if -t STDOUT; +binmode STDERR, ":encoding(console_out)" if -t STDERR; + +my %Param = (); +GetOptions( + \%Param, + # General + 'community=s', + 'version=s', + 'host=s', + 'port=s', + 'timeout=s', + # Version 3 + 'user=s', + 'authMethod=s', + 'authPass=s', + 'privMethod=s', + 'privPass=s', + 'secLevel=s', + # Operation + 'oidList=s', + 'operation=s', + # Help option + 'Help', +); + +if ($Param{Help}){ + print $HELP; + exit 0; +} + +my $config; + +# General parameters +$config->{'community'} = $Param{community} || ''; +$config->{'version'} = $Param{version} || ''; +$config->{'host'} = $Param{host} || ''; +$config->{'port'} = $Param{port} || '161'; +$config->{'timeout'} = $Param{timeout} || '2'; + +# Version 3 parameters +$config->{'auth_method'} = $Param{authMethod} || ''; +$config->{'user'} = $Param{user} || ''; +$config->{'auth_pass'} = $Param{authPass} || ''; +$config->{'priv_method'} = $Param{privMethod} || ''; +$config->{'priv_pass'} = $Param{privPass} || ''; +$config->{'sec_level'} = $Param{secLevel} || ''; + +$config->{'auth_method'} = uc($config->{'auth_method'}); +$config->{'priv_method'} = uc($config->{'priv_method'}); + +# Operation +my $operation = $Param{operation} || ''; + +# OIDs +my @oid_list = split /,/, $Param{oidList} || ''; + +# Verify parameters +if (!$config->{'host'} || !$config->{'version'} || !$operation || !@oid_list){ + print $HELP; + print "Host, version, OID list and operation are required.\n"; + exit 1; +} + +if ($config->{'version'} ne '1' && $config->{'version'} ne '2c' && $config->{'version'} ne '3'){ + print $HELP; + print "Invalid SNMP version provided.\n"; + exit 1; +} + +if ($config->{'version'} eq '1' || $config->{'version'} eq '2c'){ + if (!$config->{'community'}){ + print $HELP; + print "SNMP community required for version 1 or 2c.\n"; + exit 1; + } +} + +if ($config->{'version'} eq '3'){ + if ($config->{'sec_level'} =~ /^noAuthNoPriv$/i){ + if (!$config->{'user'}){ + print $HELP; + print "Username required for SNMP version 3 and security level 'noAuthNoPriv'.\n"; + exit 1; + } + }elsif ($config->{'sec_level'} =~ /^authNoPriv$/i){ + if (!$config->{'user'} && !$config->{'auth_pass'} && !$config->{'auth_method'}){ + print $HELP; + print "Username, authentication password and authentication method required for SNMP version 3 and security level 'authNoPriv'.\n"; + exit 1; + } + }elsif ($config->{'sec_level'} =~ /^authPriv$/i){ + if (!$config->{'user'} && !$config->{'auth_pass'} && !$config->{'auth_method'} && !$config->{'priv_pass'} && !$config->{'priv_method'}){ + print $HELP; + print "Username, authentication password, authentication method, privacy password and privacy method required for SNMP version 3 and security level 'authPriv'.\n"; + exit 1; + } + }else{ + print $HELP; + print "Invalid SNMP security level provided for version 3.\n"; + exit 1; + } + + if ($config->{'auth_method'} && $config->{'auth_method'} ne 'MD5' && $config->{'auth_method'} ne 'SHA'){ + print $HELP; + print "Invalid SNMP authentication method provided for version 3.\n"; + exit 1; + } + + if ($config->{'priv_method'} && $config->{'priv_method'} ne 'DES' && $config->{'priv_method'} ne 'AES'){ + print $HELP; + print "Invalid SNMP privacy method provided for version 3.\n"; + exit 1; + } +} + +# Verify operation (avoid code injection) +my @operation = split //, lc($operation); + +foreach my $op (@operation){ + if ($op !~ /\d/ && $op ne ' ' && $op ne '(' && $op ne ')' && $op ne '_' && $op ne '-' && $op ne '+' && $op ne '*' && $op ne '/' && $op ne 'o'){ + print $HELP; + print "Specified operation has invalid characters: " . $op . "\n"; + exit 1; + } +} + +# Create SNMP target +my ($target, $error) = new_snmp_target($config); + +if (!$target){ + print $error . "\n"; + exit 1; +} + +# Get OIDs values +my $oid_values = {}; +my $i = 1; +foreach my $oid (@oid_list){ + $oid_values->{'_o' . $i . '_'} = snmp_get($target, $oid); + $i++; +} + +# Change operation macros with values +$i = 1; +foreach my $k (keys %{$oid_values}){ + my $oid_macro = '_o' . $i . '_'; + my $value = $oid_values->{$oid_macro}; + $operation =~ s/$oid_macro/$value/g; + $i++; +} + +# Get operation result +my $result = eval $operation; +if (defined($result)){ + print $result . "\n"; +} \ No newline at end of file diff --git a/pandora_server/util/plugin/wizard_snmp_process.pl b/pandora_server/util/plugin/wizard_snmp_process.pl new file mode 100755 index 0000000000..c510de1171 --- /dev/null +++ b/pandora_server/util/plugin/wizard_snmp_process.pl @@ -0,0 +1,282 @@ +#!/usr/bin/perl +# +################################################################################ +# +# SNMP wizard process +# +# Requirements: +# Net::SNMP +# Crypt::DES +# Digest::SHA1 +# +# (c) Enrique Martin Garcia +# +# 2020/03/10 +# +################################################################################ + +use strict; +use warnings; + +use POSIX qw(strftime); + +use Encode; +use Encode::Locale; +use Getopt::Long; +use Net::SNMP; + +my $HELP=<" -version "" [SNMP] [SNMPv3] -process "" + +-host Target host +-version SNMP version (1, 2c, 3) + +-process Process name to check if is running (case sensitive) + +[SNMP] + -community Community (only version 1 and 2c) + -port Target UDP port (Default 161) + +[SNMPv3] + -user Username + -authMethod Authentication method (MD5, SHA) + -authPass Authentication password + -privMethod Privacy method (DES, AES) + -privPass Privacy password + -secLevel Security level (noAuthNoPriv, authNoPriv, authPriv) + +Example: $0 -host 192.168.80.43 -community public -version 1 -process "httpd" + +EO_HELP + +# +# FUNCTIONS +############## + +sub new_snmp_target { + my ($config) = @_; + my $target; + my $error; + + if ($config->{'version'} ne '3'){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -community => $config->{'community'} + ); + }else{ + if ($config->{'sec_level'} =~ /^noAuthNoPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'} + ); + }elsif ($config->{'sec_level'} =~ /^authNoPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'}, + -authpassword => $config->{'auth_pass'}, + -authprotocol => $config->{'auth_method'} + ); + }elsif ($config->{'sec_level'} =~ /^authPriv$/i){ + ($target, $error) = Net::SNMP->session( + -hostname => $config->{'host'}, + -port => $config->{'port'}, + -version => $config->{'version'}, + -timeout => $config->{'timeout'}, + -translate => 0, + -username => $config->{'user'}, + -authpassword => $config->{'auth_pass'}, + -authprotocol => $config->{'auth_method'}, + -privpassword => $config->{'priv_pass'}, + -privprotocol => $config->{'priv_method'} + ); + } + } + + + return ($target, $error); +} + +sub snmp_walk { + my ($target, $oid) = @_; + my $result = {}; + + my $walk = $target->get_table( + -baseoid => $oid, + ); + + if (defined($walk)){ + $result = $walk; + } + + return $result; +} + +sub snmp_get { + my ($target, $oid) = @_; + my $result = ''; + + my $get = $target->get_request( + -varbindlist => [$oid], + ); + + if (defined($get)){ + $result = $get->{$oid}; + } + + return $result; +} + +# +# MAIN +############## + +@ARGV = map { decode(locale => $_, 1) } @ARGV if -t STDIN; +binmode STDOUT, ":encoding(console_out)" if -t STDOUT; +binmode STDERR, ":encoding(console_out)" if -t STDERR; + +my %Param = (); +GetOptions( + \%Param, + # General + 'community=s', + 'version=s', + 'host=s', + 'port=s', + 'timeout=s', + # Version 3 + 'user=s', + 'authMethod=s', + 'authPass=s', + 'privMethod=s', + 'privPass=s', + 'secLevel=s', + # Process + 'process=s', + # Help option + 'Help', +); + +if ($Param{Help}){ + print $HELP; + exit 0; +} + +my $config; + +# General parameters +$config->{'community'} = $Param{community} || ''; +$config->{'version'} = $Param{version} || ''; +$config->{'host'} = $Param{host} || ''; +$config->{'port'} = $Param{port} || '161'; +$config->{'timeout'} = $Param{timeout} || '2'; + +# Version 3 parameters +$config->{'auth_method'} = $Param{authMethod} || ''; +$config->{'user'} = $Param{user} || ''; +$config->{'auth_pass'} = $Param{authPass} || ''; +$config->{'priv_method'} = $Param{privMethod} || ''; +$config->{'priv_pass'} = $Param{privPass} || ''; +$config->{'sec_level'} = $Param{secLevel} || ''; + +$config->{'auth_method'} = uc($config->{'auth_method'}); +$config->{'priv_method'} = uc($config->{'priv_method'}); + +# Operation +my $process = $Param{process} || ''; + +# Verify parameters +if (!$config->{'host'} || !$config->{'version'} || !$process){ + print $HELP; + print "Host, version and process are required.\n"; + exit 1; +} + +if ($config->{'version'} ne '1' && $config->{'version'} ne '2c' && $config->{'version'} ne '3'){ + print $HELP; + print "Invalid SNMP version provided.\n"; + exit 1; +} + +if ($config->{'version'} eq '1' || $config->{'version'} eq '2c'){ + if (!$config->{'community'}){ + print $HELP; + print "SNMP community required for version 1 or 2c.\n"; + exit 1; + } +} + +if ($config->{'version'} eq '3'){ + if ($config->{'sec_level'} =~ /^noAuthNoPriv$/i){ + if (!$config->{'user'}){ + print $HELP; + print "Username required for SNMP version 3 and security level 'noAuthNoPriv'.\n"; + exit 1; + } + }elsif ($config->{'sec_level'} =~ /^authNoPriv$/i){ + if (!$config->{'user'} && !$config->{'auth_pass'} && !$config->{'auth_method'}){ + print $HELP; + print "Username, authentication password and authentication method required for SNMP version 3 and security level 'authNoPriv'.\n"; + exit 1; + } + }elsif ($config->{'sec_level'} =~ /^authPriv$/i){ + if (!$config->{'user'} && !$config->{'auth_pass'} && !$config->{'auth_method'} && !$config->{'priv_pass'} && !$config->{'priv_method'}){ + print $HELP; + print "Username, authentication password, authentication method, privacy password and privacy method required for SNMP version 3 and security level 'authPriv'.\n"; + exit 1; + } + }else{ + print $HELP; + print "Invalid SNMP security level provided for version 3.\n"; + exit 1; + } + + if ($config->{'auth_method'} && $config->{'auth_method'} ne 'MD5' && $config->{'auth_method'} ne 'SHA'){ + print $HELP; + print "Invalid SNMP authentication method provided for version 3.\n"; + exit 1; + } + + if ($config->{'priv_method'} && $config->{'priv_method'} ne 'DES' && $config->{'priv_method'} ne 'AES'){ + print $HELP; + print "Invalid SNMP privacy method provided for version 3.\n"; + exit 1; + } +} + +# Create SNMP target +my ($target, $error) = new_snmp_target($config); + +if (!$target){ + print $error . "\n"; + exit 1; +} + +# Get all running processes +my $processes = snmp_walk($target, '.1.3.6.1.2.1.25.4.2.1.2'); + +my $result = 0; + +# Search process name +foreach my $k (keys %{$processes}){ + if ($processes->{$k} eq $process){ + $result = 1; + last; + } +} + +print $result . "\n"; \ No newline at end of file diff --git a/pandora_server/util/plugin/wizard_wmi_module.pl b/pandora_server/util/plugin/wizard_wmi_module.pl new file mode 100755 index 0000000000..3cb1661da9 --- /dev/null +++ b/pandora_server/util/plugin/wizard_wmi_module.pl @@ -0,0 +1,176 @@ +#!/usr/bin/perl +# +################################################################################ +# +# WMI wizard module +# +# Requirements: +# wmic +# +# (c) Enrique Martin Garcia +# +# 2020/03/10 +# +################################################################################ + +use strict; +use warnings; + +use POSIX qw(strftime); + +use Encode; +use Encode::Locale; +use Getopt::Long; + +use Data::Dumper; + +my $HELP=<"] -host "" [-namespace ""] -user "" -pass "" -wmiClass "" -fieldsList "" [-queryFilter ""] -operation "" + +-wmicPath Path to wmic command (Default: /usr/bin/wmic) + +-host Target host +-namespace WMI namespace +-user Windows username ([domain/]username) +-pass User password + +-wmiClass WMI class for query (Example: Win32_OperatingSystem) +-fieldsList Comma separated class fields list (Example: TotalVisibleMemorySize,FreePhysicalMemory) +-queryFilter WMI query class filter (Example: DeviceID = 3 AND DeviceType = 1) + +-operation Aritmetic operation to get data. + Macros _fN_ will be changed by fields in list. + Example: ((_f1_ - _f2_) * 100) / _f1_ + +Example: $0 -host "192.168.80.43" -user "pandora/Administrator" -pass "PandoraFMS1234" -wmiClass "Win32_OperatingSystem" -fieldsList "TotalVisibleMemorySize,FreePhysicalMemory" -operation "((_f1_ - _f2_) * 100) / _f1_" + +EO_HELP + +# +# MAIN +############## + +@ARGV = map { decode(locale => $_, 1) } @ARGV if -t STDIN; +binmode STDOUT, ":encoding(console_out)" if -t STDOUT; +binmode STDERR, ":encoding(console_out)" if -t STDERR; + +my %Param = (); +GetOptions( + \%Param, + # General + 'wmicPath=s', + 'host=s', + 'namespace=s', + 'user=s', + 'pass=s', + # Query + 'wmiClass=s', + 'fieldsList=s', + 'queryFilter=s', + # Operation + 'operation=s', + # Help option + 'Help', +); + +if ($Param{Help}){ + print $HELP; + exit 0; +} + +my $config; + +# General parameters +$config->{'wmicPath'} = $Param{wmicPath} || '/usr/bin/wmic'; +$config->{'host'} = $Param{host} || ''; +$config->{'namespace'} = $Param{namespace} || ''; +$config->{'user'} = $Param{user} || ''; +$config->{'pass'} = $Param{pass} || ''; + +# Query parameters +$config->{'wmiClass'} = $Param{wmiClass} || ''; +$config->{'queryFilter'} = $Param{queryFilter} || ''; +$config->{'fieldsList'} = $Param{fieldsList} || ''; + +# Operation +my $operation = $Param{operation} || ''; + +# Fields +my @fields_list = split /,/, $config->{'fieldsList'} || ''; + +# Verify parameters +if (!$config->{'host'} || !$config->{'user'} || !$config->{'pass'} || !$config->{'wmiClass'} || !@fields_list || !$operation){ + print $HELP; + print "Host, user, password, WMI class, fields list and operation are required.\n"; + exit 1; +} + +# Verify operation (avoid code injection) +my @operation = split //, lc($operation); + +foreach my $op (@operation){ + if ($op !~ /\d/ && $op ne ' ' && $op ne '(' && $op ne ')' && $op ne '_' && $op ne '-' && $op ne '+' && $op ne '*' && $op ne '/' && $op ne 'f'){ + print $HELP; + print "Specified operation has invalid characters: " . $op . "\n"; + exit 1; + } +} + +# Build WMI query +my $wmi_query = 'SELECT ' . $config->{'fieldsList'} . ' FROM ' . $config->{'wmiClass'} . ($config->{'queryFilter'} ? ' WHERE ' . $config->{'queryFilter'} : ''); + +# Build wmic command +my $wmi_command = $config->{'wmicPath'} . ' -U ' . $config->{'user'} . '%' . $config->{'pass'} . ($config->{'namespace'} ? ' --namespace="' . $config->{'namespace'} . '"' : '') . ' //' . $config->{'host'} . ' "' . $wmi_query . '"'; + +# Run wmic and parse output +my $output = `$wmi_command 2>/dev/null`; + +my @data = split("\n", $output); + +if ($data[0] ne 'CLASS: ' . $config->{'wmiClass'}){ + print $output; + exit 1; +} + +# Parse fields positions +my @fields_pos; + +my $i = 0; +foreach my $field (split /\|/, $data[1]){ + my $x = 1; + foreach my $f (@fields_list){ + $f =~ s/^\s*//; + $f =~ s/\s*$//; + if (lc($field) eq lc($f)){ + $fields_pos[$i] = $x; + } + $x++; + } + $i++; +} + +# Get fields values +my $fields_values = {}; +$i = 0; +foreach my $field_value (split /\|/, $data[2]){ + $fields_values->{'_f' . $fields_pos[$i] . '_'} = $field_value; + $i++; +} + +# Change operation macros with values +$i = 1; +foreach my $k (keys %{$fields_values}){ + my $field_macro = '_f' . $i . '_'; + my $value = $fields_values->{$field_macro}; + $operation =~ s/$field_macro/$value/g; + $i++; +} + +# Get operation result +my $result = eval $operation; +if (defined($result)){ + print $result . "\n"; +} \ No newline at end of file