diff --git a/extras/pandora_update_version.sh b/extras/pandora_update_version.sh index 23ea7a4627..71d29feb10 100755 --- a/extras/pandora_update_version.sh +++ b/extras/pandora_update_version.sh @@ -160,9 +160,9 @@ echo "Updating Pandora Server version..." sed -i -e "s/my\s\s*\$pandora_version\s*=.*/my \$pandora_version = \"$VERSION\";/" "$SERVER_FILE" sed -i -e "s/my\s\s*\$pandora_build\s*=.*/my \$pandora_build = \"$BUILD\";/" "$SERVER_FILE" echo "Updating DB maintenance script version..." -sed -i -e "s/my\s\s*\$version\s*=.*/my \$version = \"$VERSION PS$BUILD\";/" "$SERVER_DB_FILE" +sed -i -e "s/my\s\s*\$version\s*=.*/my \$version = \"$VERSION Build $BUILD\";/" "$SERVER_DB_FILE" echo "Updating CLI script version..." -sed -i -e "s/my\s\s*\$version\s*=.*/my \$version = \"$VERSION PS$BUILD\";/" "$SERVER_CLI_FILE" +sed -i -e "s/my\s\s*\$version\s*=.*/my \$version = \"$VERSION Build $BUILD\";/" "$SERVER_CLI_FILE" sed -i -e "s/\s*\#\s*\Version.*/\# Version $VERSION/" "$SERVER_CONF_FILE" sed -i -e "s/\s*\!define PRODUCT_VERSION.*/\!define PRODUCT_VERSION \"$VERSION\"/" "$SERVER_WIN_MPI_OPEN_FILE" sed -i -e "s/\s*\!define PRODUCT_VERSION.*/\!define PRODUCT_VERSION \"$VERSION\"/" "$SERVER_WIN_MPI_ENT_FILE" @@ -197,7 +197,7 @@ echo "Updating Pandora Unix Agent version..." sed -i -e "s/\s*use\s*constant\s*AGENT_VERSION =>.*/use constant AGENT_VERSION => '$VERSION';/" "$AGENT_UNIX_FILE" sed -i -e "s/\s*use\s*constant\s*AGENT_BUILD =>.*/use constant AGENT_BUILD => '$BUILD';/" "$AGENT_UNIX_FILE" echo "Updating Pandora Windows Agent version..." -sed -i -e "s/\s*#define\s*PANDORA_VERSION\s*.*/#define PANDORA_VERSION (\"$VERSION(Build $BUILD)\")/" "$AGENT_WIN_FILE" +sed -i -e "s/\s*#define\s*PANDORA_VERSION\s*.*/#define PANDORA_VERSION (\"$VERSION Build $BUILD\")/" "$AGENT_WIN_FILE" sed -i -e "s/{Pandora FMS Windows Agent v.*}/{Pandora FMS Windows Agent v$VERSION}/" "$AGENT_WIN_MPI_FILE" NUMERIC_VERSION=$(echo $VERSION | sed -e "s/\([0-9]*\.[0-9]*\).*/\1/") sed -i -n "1h;1!H;\${;g;s/[\r\n]InstallVersion[\r\n]{\S*}/\nInstallVersion\n{$NUMERIC_VERSION.0.0}/g;p;}" "$AGENT_WIN_MPI_FILE" diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index d5bc31c3d5..36e53ecea4 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.754-210512 +Version: 7.0NG.754-210513 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 5bceedb77b..cf86004742 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.754-210512" +pandora_version="7.0NG.754-210513" 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/pandora_agent b/pandora_agents/unix/pandora_agent index 05141afe28..248f0fd4a1 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1015,7 +1015,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.754'; -use constant AGENT_BUILD => '210512'; +use constant AGENT_BUILD => '210513'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; @@ -1229,7 +1229,8 @@ use constant MAX_LOOP_COUNTER => 1000000000; # Print usage information and exit. ################################################################################ sub print_usage () { - print "\nUsage: $0 \n\n"; + print "Pandora FMS Agent for Linux v" . AGENT_VERSION . " Build " . AGENT_BUILD . "\n\n"; + print "Usage: $0 \n\n"; print "\tPandora home is the directory where pandora_agent.conf is located,\n"; print "\tby default /etc/pandora.\n\n"; exit 1; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index 02fcf95fba..2e51763325 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.754 -%define release 210512 +%define release 210513 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 faad25be9b..7e85bcba76 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.754 -%define release 210512 +%define release 210513 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 7d404141ea..99f7f5d086 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.754" -PI_BUILD="210512" +PI_BUILD="210513" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 4f4323ebc9..d1cb263733 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{210512} +{210513} ViewReadme {Yes} diff --git a/pandora_agents/win32/main.cc b/pandora_agents/win32/main.cc index 70f35e66e9..802a4e3a65 100644 --- a/pandora_agents/win32/main.cc +++ b/pandora_agents/win32/main.cc @@ -115,8 +115,8 @@ main (int argc, char *argv[]) { return 0; } else if (_stricmp(argv[i], HELP_CMDLINE_PARAM) == 0) { /* Help parameter */ - cout << "Pandora agent for Windows. "; - cout << "Version " << getPandoraAgentVersion () << endl; + cout << "Pandora agent for Windows "; + cout << "v" << getPandoraAgentVersion () << endl << endl; cout << "Usage: " << argv[0] << " [OPTION]" << endl << endl; cout << "Available options are:" << endl; cout << "\t" << SERVICE_INSTALL_CMDLINE_PARAM; diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index e7a797dba6..57c368a773 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.754(Build 210512)") +#define PANDORA_VERSION ("7.0NG.754 Build 210513") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index e87c3b25a4..895e32ceb8 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.754(Build 210512))" + VALUE "ProductVersion", "(7.0NG.754(Build 210513))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index e8e4aadb78..f0bb243dba 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.754-210512 +Version: 7.0NG.754-210513 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 bf5d4464a2..0c82e3b4f4 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.754-210512" +pandora_version="7.0NG.754-210513" package_pear=0 package_pandora=1 diff --git a/pandora_console/extensions/realtime_graphs.php b/pandora_console/extensions/realtime_graphs.php index 86fcfc4f0e..37593d5355 100644 --- a/pandora_console/extensions/realtime_graphs.php +++ b/pandora_console/extensions/realtime_graphs.php @@ -42,6 +42,10 @@ function pandora_realtime_graphs() global $config; check_login(); + if ($config['style'] === 'pandora_black') { + ui_require_css_file('pandora_black', 'include/styles/', true); + } + $id_network = get_parameter('id_network', 0); $action = get_parameter('action', 'list'); @@ -66,8 +70,8 @@ function pandora_realtime_graphs() $long_index = []; $no_data_image = ''; - $canvas = '
'; - $canvas .= '
'; + $canvas = '
'; + $canvas .= '
'; $width = 800; $height = 300; @@ -239,7 +243,9 @@ function pandora_realtime_graphs() echo ''; echo ''; - echo ''; + if ($config['style'] !== 'pandora_black') { + echo ''; + } // Store servers timezone offset to be retrieved from js. set_js_value('timezone_offset', date('Z', time())); diff --git a/pandora_console/extras/delete_files/delete_files.txt b/pandora_console/extras/delete_files/delete_files.txt index 7e9650d18c..50d4b78c33 100644 --- a/pandora_console/extras/delete_files/delete_files.txt +++ b/pandora_console/extras/delete_files/delete_files.txt @@ -74,6 +74,10 @@ enterprise/extensions/ipam enterprise/extensions/disabled/visual_console_manager.php enterprise/extensions/visual_console_manager.php pandora_console/extensions/net_tools.php +enterprise/godmode/agentes/module_manager_editor_web.php +enterprise/include/ajax/web_server_module_debug.php +enterprise/include/class/WebServerModuleDebug.class.php +enterprise/include/styles/WebServerModuleDebug.css include/lib/WSManager.php include/lib/WebSocketServer.php include/lib/WebSocketUser.php diff --git a/pandora_console/extras/mr/47.sql b/pandora_console/extras/mr/47.sql index df29bb01ac..de803df39a 100644 --- a/pandora_console/extras/mr/47.sql +++ b/pandora_console/extras/mr/47.sql @@ -9,5 +9,10 @@ CREATE TABLE IF NOT EXISTS `tsync_queue` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field16` TEXT NOT NULL AFTER `al_field15`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field17` TEXT NOT NULL AFTER `al_field16`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field18` TEXT NOT NULL AFTER `al_field17`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field19` TEXT NOT NULL AFTER `al_field18`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field20` TEXT NOT NULL AFTER `al_field19`; COMMIT; \ No newline at end of file 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 ccb95a05c2..8f8d62f225 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 @@ -1334,6 +1334,11 @@ ALTER TABLE talert_snmp_action ADD COLUMN `al_field12` TEXT NOT NULL DEFAULT ""; ALTER TABLE talert_snmp_action ADD COLUMN `al_field13` TEXT NOT NULL DEFAULT ""; ALTER TABLE talert_snmp_action ADD COLUMN `al_field14` TEXT NOT NULL DEFAULT ""; ALTER TABLE talert_snmp_action ADD COLUMN `al_field15` TEXT NOT NULL DEFAULT ""; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field16` TEXT NOT NULL AFTER `al_field15`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field17` TEXT NOT NULL AFTER `al_field16`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field18` TEXT NOT NULL AFTER `al_field17`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field19` TEXT NOT NULL AFTER `al_field18`; +ALTER TABLE `talert_snmp_action` ADD COLUMN `al_field20` TEXT NOT NULL AFTER `al_field19`; -- ---------------------------------------------------------------------- -- Table `tserver` diff --git a/pandora_console/godmode/agentes/module_manager.php b/pandora_console/godmode/agentes/module_manager.php index d8dd0eeef2..335017ab51 100644 --- a/pandora_console/godmode/agentes/module_manager.php +++ b/pandora_console/godmode/agentes/module_manager.php @@ -1,22 +1,38 @@ '; } else { echo '
'; @@ -73,25 +89,31 @@ echo '
'; $network_available = db_get_sql( 'SELECT count(*) FROM tserver - WHERE server_type = 1' + WHERE server_type = '.SERVER_TYPE_NETWORK ); // POSTGRESQL AND ORACLE COMPATIBLE. $wmi_available = db_get_sql( 'SELECT count(*) FROM tserver - WHERE server_type = 6' + WHERE server_type = '.SERVER_TYPE_WMI ); // POSTGRESQL AND ORACLE COMPATIBLE. $plugin_available = db_get_sql( 'SELECT count(*) FROM tserver - WHERE server_type = 4' + WHERE server_type = '.SERVER_TYPE_PLUGIN ); // POSTGRESQL AND ORACLE COMPATIBLE. $prediction_available = db_get_sql( 'SELECT count(*) FROM tserver - WHERE server_type = 5' + WHERE server_type = '.SERVER_TYPE_PREDICTION +); +// POSTGRESQL AND ORACLE COMPATIBLE. +$web_available = db_get_sql( + 'SELECT count(*) +FROM tserver +WHERE server_type = '.SERVER_TYPE_WEB ); // POSTGRESQL AND ORACLE COMPATIBLE. // Development mode to use all servers. @@ -122,6 +144,10 @@ if ($prediction_available) { $modules['predictionserver'] = __('Create a new prediction server module'); } +if ($web_available) { + $modules['webserver'] = __('Create a new web Server module'); +} + if (enterprise_installed()) { set_enterprise_module_types($modules); } @@ -298,6 +324,7 @@ if ($module_action === 'delete') { switch ($config['dbtype']) { case 'mysql': case 'postgresql': + default: $result = db_process_sql_delete( 'tagente_estado', ['id_agente_modulo' => $id_agent_module_del] @@ -388,10 +415,8 @@ if ($module_action === 'delete') { } } - // Check for errors. - if ($error != 0) { - } else { + if ((int) $error == 0) { $count_correct_delete_modules++; } } @@ -489,6 +514,7 @@ switch ($sortField) { switch ($config['dbtype']) { case 'mysql': case 'postgresql': + default: $order[] = [ 'field' => 'tagente_modulo.nombre', 'order' => 'ASC', @@ -509,6 +535,7 @@ switch ($sortField) { switch ($config['dbtype']) { case 'mysql': case 'postgresql': + default: $order[] = [ 'field' => 'tagente_modulo.nombre', 'order' => 'DESC', @@ -523,6 +550,10 @@ switch ($sortField) { break; } break; + + default: + // Do none. + break; } break; @@ -543,6 +574,10 @@ switch ($sortField) { 'order' => 'DESC', ]; break; + + default: + // Do none. + break; } break; @@ -563,6 +598,10 @@ switch ($sortField) { 'order' => 'DESC', ]; break; + + default: + // Do none. + break; } break; @@ -583,6 +622,10 @@ switch ($sortField) { 'order' => 'DESC', ]; break; + + default: + // Do none. + break; } break; @@ -598,6 +641,7 @@ switch ($sortField) { switch ($config['dbtype']) { case 'mysql': case 'postgresql': + default: $order[] = [ 'field' => 'nombre', 'order' => 'ASC', @@ -622,7 +666,7 @@ if (!empty($order)) { $first = true; foreach ($order as $ord) { - if ($first) { + if ($first === true) { $first = false; } else { $order_sql .= ','; @@ -635,31 +679,35 @@ foreach ($order as $ord) { $limit = (int) $config['block_size']; $offset = (int) get_parameter('offset'); -$params = ($checked) ? 'tagente_modulo.*, tmodule_group.*' : implode( - ',', - [ - 'tagente_modulo.id_agente_modulo', - 'id_tipo_modulo', - 'descripcion', - 'nombre', - 'max', - 'min', - 'module_interval', - 'id_modulo', - 'id_module_group', - 'disabled', - 'max_warning', - 'min_warning', - 'str_warning', - 'max_critical', - 'min_critical', - 'str_critical', - 'quiet', - 'critical_inverse', - 'warning_inverse', - 'id_policy_module', - ] -); +if ((bool) $checked === true) { + $params = 'tagente_modulo.*, tmodule_group.*'; +} else { + $params = implode( + ',', + [ + 'tagente_modulo.id_agente_modulo', + 'id_tipo_modulo', + 'descripcion', + 'nombre', + 'max', + 'min', + 'module_interval', + 'id_modulo', + 'id_module_group', + 'disabled', + 'max_warning', + 'min_warning', + 'str_warning', + 'max_critical', + 'min_critical', + 'str_critical', + 'quiet', + 'critical_inverse', + 'warning_inverse', + 'id_policy_module', + ] + ); +} $where = sprintf('delete_pending = 0 AND id_agente = %s', $id_agente); @@ -686,7 +734,11 @@ if (isset($config['paginate_module'])) { if ($paginate_module) { if (!isset($limit_sql)) { - $limit_sql = " LIMIT $offset, $limit "; + $limit_sql = sprintf( + 'LIMIT %s, %s', + $offset, + $limit + ); } } else { $limit_sql = ''; @@ -732,7 +784,13 @@ if ($modules === false) { } // Prepare pagination. -$url = '?'.'sec=gagente&'.'tab=module&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$id_agente.'&'.'sort_field='.$sortField.'&'.'&sort='.$sort.'&'.'search_string='.urlencode($search_string); +$url = sprintf( + '?sec=gagente&tab=module&sec2=godmode/agentes/configurar_agente&id_agente=%s&sort_field=%s&sort=%s&search_string=%s', + $id_agente, + $sortField, + $sort, + urlencode($search_string) +); if ($paginate_module) { ui_pagination($total_modules, $url); diff --git a/pandora_console/godmode/agentes/module_manager_editor.php b/pandora_console/godmode/agentes/module_manager_editor.php index c350866cf0..1310fa80bb 100644 --- a/pandora_console/godmode/agentes/module_manager_editor.php +++ b/pandora_console/godmode/agentes/module_manager_editor.php @@ -682,6 +682,22 @@ switch ($moduletype) { include 'module_manager_editor_wmi.php'; break; + case 'webserver': + case MODULE_WEB: + $moduletype = MODULE_WEB; + // Remove content of $ip_target when it is ip_agent because + // it is used as HTTP auth (server) ....ONLY IN NEW MODULE!!! + if (empty($id_agent_module) + && ($ip_target === agents_get_address($id_agente)) + ) { + $ip_target = ''; + } + + $categories = [9]; + include 'module_manager_editor_common.php'; + include 'module_manager_editor_web.php'; + break; + // WARNING: type 7 is reserved on enterprise. default: if (enterprise_include( diff --git a/pandora_console/godmode/agentes/module_manager_editor_web.php b/pandora_console/godmode/agentes/module_manager_editor_web.php new file mode 100644 index 0000000000..3d02289160 --- /dev/null +++ b/pandora_console/godmode/agentes/module_manager_editor_web.php @@ -0,0 +1,468 @@ + 'modal', + 'style' => 'display: none;', + ] +); + +require_once $config['homedir'].'/include/ajax/web_server_module_debug.php'; + +define('ID_NETWORK_COMPONENT_TYPE', 7); + +if (!$tcp_port && !$id_agent_module) { + $tcp_port = 80; +} + +// plugin_server is the browser id +if ($plugin_user == '' && !$id_agent_module) { + $plugin_user = get_product_name().' / Webcheck'; +} + +// plugin_server is the referer +if ($plugin_pass == '' && !$id_agent_module) { + $plugin_pass = 1; +} + +if (empty($update_module_id)) { + // Function in module_manager_editor_common.php + add_component_selection(ID_NETWORK_COMPONENT_TYPE); +} else { + // TODO: Print network component if available +} + +$data = []; +$data[0] = __('Web checks'); + +$adopt = false; +if (isset($id_agent_module)) { + $adopt = enterprise_hook('policies_is_module_adopt', [$id_agent_module]); +} + +$id_policy_module = (int) get_parameter('id_policy_module', ''); +if ($id_policy_module) { + $module = enterprise_hook('policies_get_module', [$id_policy_module]); + $plugin_parameter = $module['plugin_parameter']; +} + +if ((bool) $adopt === false) { + $data[1] = html_print_textarea( + 'plugin_parameter', + 15, + 65, + $plugin_parameter, + $disabledTextBecauseInPolicy, + true + ); +} else { + $data[1] = html_print_textarea( + 'plugin_parameter', + 15, + 65, + $plugin_parameter, + false, + true + ); +} + +$table_simple->colspan['web_checks'][1] = 2; + +// Disable debug button if module has not started. +if ($id_agent_module > 0 + && db_get_value_filter( + 'debug_content', + 'tagente_modulo', + ['id_agente_modulo' => $id_agent_module] + ) !== null +) { + $disableDebug = false; + $hintDebug = __('Debug remotely this module'); +} else { + $disableDebug = true; + $hintDebug = __('Debug this module once it has been initialized'); +} + +$suc_err_check = ' '; +$suc_err_check .= ' '; +$data[2] = html_print_button( + __('Load basic'), + 'btn_loadbasic', + false, + '', + 'class="sub config"', + true +).ui_print_help_tip(__('Load a basic structure on Web Checks'), true); +$data[2] .= '

'.html_print_button( + __('Check'), + 'btn_checkconf', + false, + '', + 'class="sub upd"', + true +).ui_print_help_tip(__('Check the correct structure of the WebCheck'), true).$suc_err_check; +$data[2] .= '

'.html_print_button( + __('Debug'), + 'btn_debugModule', + $disableDebug, + '', + 'class="sub config" onClick="loadDebugWindow()"', + true +).ui_print_help_tip($hintDebug, true); + + +push_table_simple($data, 'web_checks'); + +$http_checks_type = [ + 0 => 'Anyauth', + 1 => 'NTLM', + 2 => 'DIGEST', + 3 => 'BASIC', +]; + +$data = []; +$data[0] = __('Check type'); +$data[1] = html_print_select($http_checks_type, 'tcp_port', $tcp_port, false, '', '', true, false, false); + +push_table_advanced($data, 'web_0'); + +$data = []; +$data[0] = __('Requests'); +$data[1] = html_print_input_text('plugin_pass', $plugin_pass, '', 10, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); +$data[2] = ''; +$data[3] = __('Agent browser id'); +$data[4] = html_print_input_text('plugin_user', $plugin_user, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +push_table_advanced($data, 'web_1'); + +$data = []; +$data[0] = __('HTTP auth (login)'); +$data[1] = html_print_input_text('http_user', $plugin_parameter_http_user, '', 10, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); +$data[2] = ''; +$data[3] = __('HTTP auth (password)'); +$data[4] = html_print_input_password('http_pass', $plugin_parameter_http_pass, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +push_table_advanced($data, 'web_2'); + +$data = []; + +$data[0] = __('Proxy URL'); +$data[1] = html_print_input_text('snmp_oid', $snmp_oid, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); +$data[2] = $data[3] = $data[4] = ''; +push_table_advanced($data, 'web_3'); + +$data = []; + +$data[0] = __('Proxy auth (login)'); +$data[1] = html_print_input_text('tcp_send', $tcp_send, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +$data[2] = ''; +$data[3] = __('Proxy auth (pass)'); +$data[4] = html_print_input_password('tcp_rcv', $tcp_rcv, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +push_table_advanced($data, 'web_4'); + +$data = []; + +$data[0] = __('Proxy auth (server)'); +$data[1] = html_print_input_text('ip_target', $ip_target, '', 30, 100, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +$data[2] = ''; +$data[3] = __('Proxy auth (realm)'); +$data[4] = html_print_input_text('snmp_community', $snmp_community, '', 30, 100, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); + +push_table_advanced($data, 'web_5'); + +// Add some strings to be used from javascript +$texts = [ + 'lines_before_begin' => __('First line must be "task_begin"'), + 'missed_begin' => __('Webchecks configuration is empty'), + 'missed_end' => __('Last line must be "task_end"'), + 'lines_after_end' => __('Last line must be "task_end"'), + 'unknown_token' => __("There is a line with a unknown token 'token_fail'."), + 'missed_get_post' => __("There isn't get or post"), + 'correct' => __('Web checks are built correctly'), +]; + +foreach ($texts as $code => $text) { + echo ''; +} +?> + \ No newline at end of file diff --git a/pandora_console/include/ajax/web_server_module_debug.php b/pandora_console/include/ajax/web_server_module_debug.php new file mode 100644 index 0000000000..36d82165fe --- /dev/null +++ b/pandora_console/include/ajax/web_server_module_debug.php @@ -0,0 +1,74 @@ + '[WebServerModuleDebug]'.$e->getMessage() ]); + exit; + } else { + echo '[WebServerModuleDebug]'.$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/include/class/WebServerModuleDebug.class.php b/pandora_console/include/class/WebServerModuleDebug.class.php new file mode 100644 index 0000000000..e0e6f23c84 --- /dev/null +++ b/pandora_console/include/class/WebServerModuleDebug.class.php @@ -0,0 +1,407 @@ + 'noaccess']); + } + + include 'general/noaccess.php'; + exit; + } + + // Parameter assigments. + $this->ajaxController = $ajaxController; + $this->query = ''; + $this->idAgentModule = $idAgentModule; + // Hardcoded request timeout. + $this->requestTimeout = 15; + + return $this; + + } + + + /** + * Run Module Debug window. + * + * @return void + */ + public function run() + { + // Added all necessary basic files for QueryResult. + ui_require_css_file('ace'); + ui_require_javascript_file('ace', 'include/javascript/ace/'); + // Load Javascript. + $this->loadJS(); + // CSS. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + // Specific CSS for this feature. + ui_require_css_file('WebServerModuleDebug', '/include/styles/', true); + + } + + + /** + * Show the modal with the QueryResult. + * + * @return void + */ + public function showWebServerDebug() + { + // Show QueryResult editor. + ui_query_result_editor('webserverdebug'); + // Spinner for wait loads. + html_print_div( + [ + 'id' => 'WebServerDebugSpinner', + 'style' => 'visibility: hidden;', + 'content' => __('Performing query. Please wait.').' '.html_print_image('images/spinner.gif', true), + ] + ); + ?> + + + + $this->idAgentModule, + ] + ); + + $this->query = ($outputDebugQuery !== false) ? $outputDebugQuery : __('Please, wait for a first execution of module'); + + return $this->query; + } + + + /** + * Perform the cURL execution. + * + * @return void + * @throws Exception $e Error message. + */ + public function executeCommand() + { + try { + $executionForPerform = io_safe_output(get_parameter('text')); + // If the execution comes empty. + if (empty($executionForPerform) === true) { + throw new Exception('Execution failed'); + } + + // For security reasons, only allow the 'curl' command. + $executionForPerform = strstr($executionForPerform, 'curl'); + // Avoid pipes or concatenation of commands. + $unallowedChars = [ + '|', + '&', + '||', + '&&', + ';', + '\n', + ]; + $executionForPerform = str_replace( + $unallowedChars, + ' ', + $executionForPerform + ); + // Set execution timeout. + $executionForPerform .= sprintf( + $executionForPerform.' -m %d', + $this->requestTimeout + ); + + // Perform the execution. + system($executionForPerform, $returnCode); + // If execution does not got well. + if ($returnCode != 0) { + switch ($returnCode) { + case '2': + throw new Exception('Failed to initialize. Review the syntax.'); + + case '3': + throw new Exception('URL malformed. The syntax was not correct.'); + + case '5': + throw new Exception('Couldn\'t resolve proxy. The given proxy host could not be resolved.'); + + case '6': + throw new Exception('Couldn\'t resolve host. The given remote host could not be resolved.'); + + case '7': + throw new Exception('Failed to connect to host.'); + + default: + throw new Exception('Failed getting data.'); + } + } + } catch (Exception $e) { + // Show execution error message. + echo __($e->getMessage()); + } + + exit; + } + + + /** + * Loads JS and return code. + * + * @return string + */ + public function loadJS() + { + $str = ''; + ob_start(); + ?> + + + + '; +if ($config['style'] === 'pandora_black') { + ui_require_css_file('pandora_black', 'include/styles/', true); +} $interface_name = (string) $params['interface_name']; $agent_id = (int) $params['agent_id']; @@ -190,6 +193,7 @@ $data[1] .= html_print_image( [ 'onclick' => "scwShow(scwID('text-start_date'),this);", 'style' => 'vertical-align: bottom;', + 'class' => 'invert_filter', ], false, false, @@ -251,7 +255,8 @@ $options[2] = 'x2'; $options[3] = 'x3'; $options[4] = 'x4'; $options[5] = __('Full'); -$data[1] = html_print_select( +/* + $data[1] = html_print_select( $options, 'zoom', $zoom, @@ -261,9 +266,9 @@ $data[1] = html_print_select( true, false, false -); -$table->data[] = $data; -$table->rowclass[] = ''; + ); + $table->data[] = $data; +$table->rowclass[] = '';*/ $form_table = html_print_table($table, true); $form_table .= '
'; @@ -284,7 +289,7 @@ if (empty($server_id) === false) { $menu_form .= html_print_input_hidden('server', $server_id, true); } -$menu_form .= '
'; +$menu_form .= '
'; $menu_form .= '
'; $menu_form .= html_print_image( 'images/arrow_down_green.png', @@ -312,13 +317,6 @@ $menu_form .= '
'; $menu_form .= ''; echo $menu_form; -echo '
-
- '.html_print_image('images/arrow_down_green.png', true, ['class' => 'module_graph_menu_arrow', 'float' => 'left'], false, false, true).' - '.__('Graph configuration menu').'
- -
'; -echo ''; // Hidden div to forced title. html_print_div( diff --git a/pandora_console/operation/agentes/pandora_networkmap.editor.php b/pandora_console/operation/agentes/pandora_networkmap.editor.php index 4937b3d38f..8f735e72de 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.editor.php +++ b/pandora_console/operation/agentes/pandora_networkmap.editor.php @@ -390,7 +390,7 @@ if ($not_found) { 'circo' => 'circular', 'neato' => 'spring1', 'fdp' => 'spring2', - 'radial_dinamic' => 'radial dinamic', + 'radial_dinamic' => 'radial dynamic', ]; $table->data[7][0] = __('Method generation networkmap'); diff --git a/pandora_console/operation/agentes/realtime_win.php b/pandora_console/operation/agentes/realtime_win.php index 53837e7c5b..0068fb7425 100644 --- a/pandora_console/operation/agentes/realtime_win.php +++ b/pandora_console/operation/agentes/realtime_win.php @@ -64,6 +64,10 @@ if (file_exists('../../include/languages/'.$user_language.'.mo')) { $l10n->load_tables(); } +if ($config['style'] === 'pandora_black') { + ui_require_css_file('pandora_black', 'include/styles/', true); +} + echo ''; ?> @@ -92,6 +96,10 @@ echo ' 0x01; @@ -123,6 +124,7 @@ sub pandora_startup () { push (@Servers, new PandoraFMS::WMIServer (\%Config, $DBH)); push (@Servers, new PandoraFMS::PluginServer (\%Config, $DBH)); push (@Servers, new PandoraFMS::PredictionServer (\%Config, $DBH)); + push (@Servers, new PandoraFMS::WebServer (\%Config, $DBH)); } else { # Metaconsole service modules are run by the prediction server push (@Servers, new PandoraFMS::PredictionServer (\%Config, $DBH)); diff --git a/pandora_server/conf/pandora_server.conf.new b/pandora_server/conf/pandora_server.conf.new index 2b80300950..86da53430e 100644 --- a/pandora_server/conf/pandora_server.conf.new +++ b/pandora_server/conf/pandora_server.conf.new @@ -25,6 +25,7 @@ incomingdir /var/spool/pandora/data_in log_file /var/log/pandora/pandora_server.log # Log file for Pandora FMS SNMP console. Its generated by NetSNMP Trap daemon +# If you change it, please update the file /etc/logrotate.d/pandora_server accordingly. snmp_logfile /var/log/pandora/pandora_snmptrap.log @@ -424,11 +425,11 @@ update_parent 1 # openstreetmaps_description 1 -# Enable (1) or disable (0) Pandora FMS Web Server/Goliat (PANDORA FMS ENTERPRISE ONLY). +# Enable (1) or disable (0) Pandora FMS Web Server/Goliat. webserver 1 -# Number of threads for the Web Server/Goliat (PANDORA FMS ENTERPRISE ONLY). +# Number of threads for the Web Server/Goliat. web_threads 1 diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index 7021463a50..cf8e4bc2e7 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.754"; -my $pandora_build = "210512"; +my $pandora_build = "210513"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash @@ -77,7 +77,7 @@ sub help_screen { sub pandora_init { my $pa_config = $_[0]; my $init_string = $_[1]; - print "\n$init_string $pandora_version Build $pandora_build Copyright (c) 2004-20".substr($pandora_build,0,2)." " . pandora_get_initial_copyright_notice() . "\n"; + print "$init_string v$pandora_version Build $pandora_build\n\n"; print "This program is OpenSource, licensed under the terms of GPL License version 2.\n"; print "You can download latest versions and documentation at official web page.\n\n"; diff --git a/pandora_server/lib/PandoraFMS/Core.pm b/pandora_server/lib/PandoraFMS/Core.pm index b3f8db192a..a384d3701e 100644 --- a/pandora_server/lib/PandoraFMS/Core.pm +++ b/pandora_server/lib/PandoraFMS/Core.pm @@ -4031,6 +4031,12 @@ sub pandora_evaluate_snmp_alerts ($$$$$$$$$) { $alert->{'al_field13'} = subst_alert_macros ($alert->{'al_field13'}, \%macros); $alert->{'al_field14'} = subst_alert_macros ($alert->{'al_field14'}, \%macros); $alert->{'al_field15'} = subst_alert_macros ($alert->{'al_field15'}, \%macros); + $alert->{'al_field16'} = subst_alert_macros ($alert->{'al_field16'}, \%macros); + $alert->{'al_field17'} = subst_alert_macros ($alert->{'al_field17'}, \%macros); + $alert->{'al_field18'} = subst_alert_macros ($alert->{'al_field18'}, \%macros); + $alert->{'al_field19'} = subst_alert_macros ($alert->{'al_field19'}, \%macros); + $alert->{'al_field20'} = subst_alert_macros ($alert->{'al_field20'}, \%macros); + # Check time threshold $alert->{'last_fired'} = '1970-01-01 00:00:00' unless defined ($alert->{'last_fired'}); @@ -4070,6 +4076,14 @@ sub pandora_evaluate_snmp_alerts ($$$$$$$$$) { 'field13' => $alert->{'al_field13'}, 'field14' => $alert->{'al_field14'}, 'field15' => $alert->{'al_field15'}, + 'field16' => $alert->{'al_field16'}, + 'field17' => $alert->{'al_field17'}, + 'field18' => $alert->{'al_field18'}, + 'field19' => $alert->{'al_field19'}, + 'field20' => $alert->{'al_field20'}, + + + 'description' => $alert->{'description'}, 'times_fired' => $times_fired, 'time_threshold' => 0, @@ -4155,6 +4169,12 @@ sub pandora_evaluate_snmp_alerts ($$$$$$$$$) { 'field13' => $other_alert->{'al_field13'}, 'field14' => $other_alert->{'al_field14'}, 'field15' => $other_alert->{'al_field15'}, + 'field16' => $other_alert->{'al_field16'}, + 'field17' => $other_alert->{'al_field17'}, + 'field18' => $other_alert->{'al_field18'}, + 'field19' => $other_alert->{'al_field19'}, + 'field20' => $other_alert->{'al_field20'}, + 'description' => '', 'times_fired' => $times_fired, 'time_threshold' => 0, diff --git a/pandora_server/lib/PandoraFMS/Goliat/GoliatCURL.pm b/pandora_server/lib/PandoraFMS/Goliat/GoliatCURL.pm new file mode 100755 index 0000000000..63fe5ca5de --- /dev/null +++ b/pandora_server/lib/PandoraFMS/Goliat/GoliatCURL.pm @@ -0,0 +1,365 @@ +################################################################################## +# Goliath Tools CURL Module +################################################################################## +# Copyright (c) 2013-2021 Artica Soluciones Tecnologicas S.L +# This code is not free or OpenSource. Please don't redistribute. +################################################################################## + +package PandoraFMS::Goliat::GoliatCURL; + +use PandoraFMS::Goliat::GoliatTools; + +use strict; +use warnings; +use Data::Dumper; +use PandoraFMS::DB; + +use IO::Socket::INET6; +use URI::Escape; +use Time::Local; +use Time::HiRes qw ( gettimeofday ); + +# Japanese encoding support +use Encode::Guess qw/euc-jp shiftjis iso-2022-jp/; + +require Exporter; + +our @ISA = ("Exporter"); +our %EXPORT_TAGS = ( 'all' => [ qw() ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = qw( + g_http_task + @task_requests + @task_reqsec + @task_fails + @task_time + @task_end + @task_sessions + @task_ssec + @task_get_string + @task_get_content + @task_session_fails +); + +our @task_requests; +our @task_reqsec; +our @task_fails ; +our @task_time; +our @task_end; +our @task_sessions; +our @task_ssec; +our @task_get_string; +our @task_get_content; +our @task_session_fails; +our $goliat_abort; + +# Returns a string than can be safely used as a command line parameter for CURL +sub safe_param ($) { + my $string = shift; + + $string =~ s/'/"/g; + return "'" . $string . "'"; +} + +sub g_http_task { + my ( $config, $thread_id, @work_list ) = @_; + my ( $ax, $bx, $cx ); # used in FOR loop + my ( $ttime1, $ttime2, $ttime_tot ); + + my $resp; # HTTP Response + my $total_requests = 0; + my $total_valid_requests = 0; + my $total_invalid_request = 0; + my $cookie_file = "/tmp/gtc_".$thread_id."_".g_trash_ascii (3); + my $check_string = 1; + my $get_string = ""; + my $get_content = ""; + my $get_content_advanced = ""; + my $timeout = 10; + + #my $ua = new LWP::UserAgent; + $task_requests [$thread_id] = 0 ; + $task_sessions [$thread_id] = 0 ; + $task_reqsec[$thread_id] = 0; + $task_fails[$thread_id] = 0; + $task_session_fails[$thread_id] = 0; + $task_ssec[$thread_id] = 0; + $task_end[$thread_id] = 0; + $task_time[$thread_id] = 0; + $task_get_string[$thread_id] = ""; + $task_get_content[$thread_id] = ""; + + # Set command line options for CURL + my $curl_opts; + + # Follow redirects + $curl_opts .= " --location-trusted"; + + # User agent + if ($config->{"agent"} ne '') { + $curl_opts .= " -A " . safe_param($config->{"agent"}) + } + + # Prevent pages from being cached + $curl_opts .= " -H 'Pragma: no-cache'"; + + # Timeout + if (defined ($config->{"timeout"}) && $config->{"timeout"} > 0) { + $timeout = $config->{"timeout"}; + } + + # Maximum file size + if (defined($config->{"maxsize"}) && $config->{"maxsize"} > 0) { + $curl_opts .= " --max-filesize " . $config->{"maxsize"}; + } + + # Disable SSL certificate host verification + $curl_opts .= " -k"; + + # Proxy + if ($config->{'proxy'} ne ""){ + $curl_opts .= " -x " . safe_param($config->{'proxy'}); + } + + # Proxy HTTP authentication + if ($config->{'auth_user'} ne "") { + $curl_opts .= " --proxy-anyauth -U " . safe_param($config->{'auth_user'} . ':' . $config->{'auth_pass'}); + } + + # Delete existing cookies + my $cookie_carry_on = 0; + if ( -e $cookie_file){ + unlink ($cookie_file); + } + + $ttime1 = Time::HiRes::gettimeofday(); + for ($ax = 0; $ax != $config->{'retries'}; $ax++){ + for ($bx = 0; $bx < $config->{"work_items"}; $bx++){ + if ($config->{'con_delay'} > 0){ + sleep ($config->{'con_delay'}); + } + $total_requests++; + # Start to count! + $check_string = 1; + # Prepare parameters + my $task_curl_opts = $curl_opts; + my $params = ""; + $cx = 0; + while (defined($work_list[$bx]->{'variable_name'}[$cx])){ + if ($cx > 0){ + $params = $params."&"; + } + $params = $params . $work_list[$bx]->{'variable_name'}[$cx] . "=" . uri_escape($work_list[$bx]->{'variable_value'}[$cx]); + $cx++; + } + + # Cookie carry on + if (defined ($work_list[$bx]->{'cookie'}) && $work_list[$bx]->{'cookie'} == 1){ + $cookie_carry_on = 1; + } + + if ($cookie_carry_on == 1) { + $task_curl_opts .= " -c " . safe_param ($cookie_file); + $task_curl_opts .= " -b " . safe_param ($cookie_file); + } + + # HTTP authentication + if ($work_list[$bx]->{'http_auth_user'} ne "" && $work_list[$bx]->{'http_auth_pass'} ne "") { + + if($config->{'http_check_type'} == 0){ + $task_curl_opts .= " --anyauth -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'}); + } + + if ($config->{'http_check_type'} == 1) { + $task_curl_opts .= " --ntlm -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'}); + } + + if ($config->{'http_check_type'} == 2) { + $task_curl_opts .= " --digest -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'}); + } + + if ($config->{'http_check_type'} == 3) { + $task_curl_opts .= " --basic -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'}); + } + + + } + + # GET + if ($work_list[$bx]->{'type'} eq "GET"){ + $task_curl_opts .= " -H 'Accept: text/html'"; + if ($cx > 0){ + $params = $work_list[$bx]->{'url'} . "?" . $params; + } else { + $params = $work_list[$bx]->{'url'}; + } + + $resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"}); + + # POST + } elsif ($work_list[$bx]->{'type'} eq "POST") { + $task_curl_opts .= " -d " . safe_param($params); + $task_curl_opts .= " -H 'Content-type: application/x-www-form-urlencoded'"; + $resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"}); + + # HEAD + } else { + $task_curl_opts .= " -I"; + if ($cx > 0){ + $params = $work_list[$bx]->{'url'} . "?" . uri_escape($params); + } else { + $params = $work_list[$bx]->{'url'}; + } + $resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"}); + } + + # Get string ? + if (defined($work_list[$bx]->{'get_string'})) { + my $temp = $work_list[$bx]->{'get_string'}; + if ($resp =~ m/($temp)/) { + $task_get_string[$thread_id] = $1; + } + } + + # Get response ? + if ($work_list[$bx]->{'get_content_advanced'} ne "") { + my $temp = $work_list[$bx]->{'get_content_advanced'}; + if ($resp =~ m/$temp/) { + $task_get_content[$thread_id] = $1 if defined ($1); + } + } elsif ($work_list[$bx]->{'get_content'} ne "") { + my $temp = $work_list[$bx]->{'get_content'}; + if ($resp =~ m/($temp)/) { + $task_get_content[$thread_id] = $1; + } + } else { + $task_get_content[$thread_id] = $resp; + } + + # Resource bashing + #if ((defined($work_list[$bx]->{'get_resources'})) && ($work_list[$bx]->{'get_resources'} == 1)){ + # $total_requests = g_get_all_links ($config, $ua, $resp, $total_requests, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}); + #} + + # CHECKSTRING check + $cx = 0; + while (defined($work_list[$bx]->{'checkstring'}[$cx])) { + my $match_string = $work_list[$bx]->{'checkstring'}[$cx]; + my $as_string = $resp; + my $guess = Encode::Guess::guess_encoding($as_string); + if (ref $guess) { + $as_string = $guess->decode($as_string); + } + unless (utf8::is_utf8($match_string)) { + utf8::decode($match_string); + } + + if ( $as_string =~ m/$match_string/i ){ + $total_valid_requests++; + } else { + $total_invalid_request++; + $bx = $config->{"work_items"}; # Abort session remaining request + $check_string=0; + } + $cx++; + } + + # CHECKNOTSTRING check + $cx = 0; + while (defined($work_list[$bx]->{'checknotstring'}[$cx])) { + my $match_string = $work_list[$bx]->{'checknotstring'}[$cx]; + my $as_string = $resp; + + my $guess = Encode::Guess::guess_encoding($as_string); + if (ref $guess) { + $as_string = $guess->decode($as_string); + } + unless (utf8::is_utf8($match_string)) { + utf8::decode($match_string); + } + + if ( $as_string !~ m/$match_string/i ){ + $total_valid_requests++; + } else { + $total_invalid_request++; + $bx = $config->{"work_items"}; # Abort session remaining request + $check_string=0; + } + $cx++; + } + + # End just now by pressing CTRL-C or Kill Signal ! + #if ($goliat_abort == 1){ + #$ax = $config->{'retries'}; + #$bx = $config->{'items'}; + #goto END_LOOP; + #} + } #main work_detail loop + $ttime2 = Time::HiRes::gettimeofday(); + + $ttime_tot = $ttime2 - $ttime1; # Total time for this task + $task_time[$thread_id] = $ttime_tot; + $task_requests [$thread_id] = $total_requests; + if ($ttime_tot > 0 ){ + $task_reqsec[$thread_id] = $total_requests / $ttime_tot; + } else { + $task_reqsec[$thread_id] = $total_requests; + } + $task_fails[$thread_id] = $total_invalid_request; + if ($check_string == 0){ + $task_session_fails[$thread_id]++ + } + $task_sessions [$thread_id]++; + if ($task_sessions [$thread_id] > 0 ){ + $task_ssec[$thread_id] = $ttime_tot / $task_sessions [$thread_id]; + } else { + $task_ssec[$thread_id] = $task_sessions[$thread_id]; + } + sleep $config->{'ses_delay'}; + } +END_LOOP: + + if ( -f $cookie_file){ + unlink ($cookie_file); + } + + $task_end[$thread_id] = 1; +} + +# Call CURL and return its output. +sub curl { + my ($exec, $timeout, $curl_opts, $url, $headers, $debug, $moduleId, $dbh) = @_; + + while (my ($header, $value) = each %{$headers}) { + $curl_opts .= " -H " . safe_param($header . ':' . $value); + } + + my $cmd = "curl $curl_opts " . safe_param($url); + my $response = `"$exec" $timeout $cmd 2>/dev/null`; + + # Curl command stored for live debugging feature. + set_update_agentmodule ($dbh, $moduleId, { 'debug_content' => $cmd }) if defined($dbh); + + return $response if ($debug eq ''); + + # Debug + if (open (DEBUG, '>>', $debug . '.req')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $cmd; + print "\n"; + close (DEBUG); + } + if (open (DEBUG, '>>', $debug . '.res')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $response; + print "\n"; + close (DEBUG); + } + return $response; +} + +# End of function declaration +# End of defined Code + +1; +__END__ diff --git a/pandora_server/lib/PandoraFMS/Goliat/GoliatConfig.pm b/pandora_server/lib/PandoraFMS/Goliat/GoliatConfig.pm new file mode 100755 index 0000000000..da3247c1e8 --- /dev/null +++ b/pandora_server/lib/PandoraFMS/Goliat/GoliatConfig.pm @@ -0,0 +1,265 @@ +########################################################################## +# Goliat Config package +########################################################################## +# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L +# This code is not free or OpenSource. Please don't redistribute. +########################################################################## + +package PandoraFMS::Goliat::GoliatConfig; + +use strict; +use warnings; +use PandoraFMS::Tools; +use PandoraFMS::Goliat::GoliatTools; + +require Exporter; +our @ISA = ("Exporter"); +our %EXPORT_TAGS = ( 'all' => [ qw( ) ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = qw( g_help_screen + g_init + g_load_config ); + +my $g_version = "1.0"; +my $g_build = "110929"; +our $VERSION = $g_version." ".$g_build; + + +sub g_load_config { + my ( $config , $work_list )= @_ ; + my $archivo_cfg = $config->{'config_file'}; + my $buffer_line; + my $task_block = 0; + my $commit_block = 0; + my $task_url = ""; + my $task_cookie = 0; + my $task_resources = 1; + my $task_type = ""; + my $task_headers = {}; + my $task_debug = ""; + my $http_auth_user = ""; + my $http_auth_pass = ""; + my $http_auth_realm = ""; + my $http_auth_serverport = ""; + my $get_string = ""; + my $get_content = ""; + my $get_content_advanced = ""; + my @task_variable_name; + my @task_variable_value; + my @task_check_string; + my @task_check_not_string; + my $parametro; + my $temp1; + + # Default options + $config->{'con_delay'} =0; + $config->{'ses_delay'} =0; + if (!defined($config->{'agent'})){ + $config->{'agent'}="PandoraFMS/Goliat 4.0; Linux)"; + } + if (!defined($config->{'proxy'})){ + $config->{'proxy'}=""; + } + + if (!defined($config->{'retries'})){ + $config->{'retries'} = 1; + } + + if ((!is_numeric($config->{'retries'})) || ($config->{'retries'} == 0)){ + $config->{'retries'} = 1; + } + + $config->{'refresh'} = "5"; + $config->{"max_depth"} = 25; + $config->{'log_file'}="/var/log/pandora/pandora_goliat.log"; + $config->{'log_output'} = 0; + + # Collect items from config file and put in an array + open (CFG, "< $archivo_cfg"); + while (){ + $buffer_line = $_; + if ($buffer_line =~ /^[a-zA-Z]/){ # begins with letters + $parametro = $buffer_line; + } else { + $parametro = ""; + } + # Need to commit block ?? + if (($commit_block == 1) && ($task_block == 1)) { + my %work_item; + $work_item{'url'} = $task_url; + $work_item{'cookie'} = $task_cookie; + $work_item{'type'} = $task_type; + $work_item{'get_resources'} = $task_resources; + $work_item{'get_string'} = $get_string; + $work_item{'get_content'} = $get_content; + $work_item{'get_content_advanced'} = $get_content_advanced; + $work_item{'http_auth_user'} = $http_auth_user; + $work_item{'http_auth_pass'} = $http_auth_pass; + $work_item{'http_auth_realm'} = $http_auth_realm; + $work_item{'http_auth_serverport'} = $http_auth_serverport; + $work_item{'headers'} = $task_headers; + $work_item{'debug'} = $task_debug; + + my $ax=0; + while ($#task_check_string >= 0){ + $temp1 = pop (@task_check_string); + $work_item{'checkstring'}[$ax] = $temp1; + $ax++; + } + $ax=0; + while ($#task_check_not_string >= 0){ + $temp1 = pop (@task_check_not_string); + $work_item{'checknotstring'}[$ax] = $temp1; + $ax++; + } + $ax=0; + while ($#task_variable_name >= 0){ + $temp1 = pop (@task_variable_name); + $work_item{'variable_name'}[$ax] = $temp1; + $ax++; + } + $ax=0; + while ($#task_variable_value >= 0){ + $temp1 = pop (@task_variable_value); + $work_item{'variable_value'}[$ax] = $temp1; + $ax++; + + } + push @{$work_list}, \%work_item; + $commit_block = 0; + $task_block = 0; + $task_url = ""; + $task_cookie = 0; + $task_resources = 0; + $task_type = ""; + $task_headers = {}; + $task_debug = ""; + $config->{"work_items"}++; + $commit_block = 0; + $task_block = 0; + $http_auth_user = ""; + $http_auth_pass = ""; + $http_auth_realm = ""; + $get_string = ""; + $get_content = ""; + $get_content_advanced = ""; + } + # ~~~~~~~~~~~~~~ + # Main setup items + # ~~~~~~~~~~~~~~ + + if ($parametro =~ m/^task_begin/i) { + $task_block = 1; + } + elsif ($parametro =~ m/^task_end/i) { + $commit_block = 1; + } + elsif ($parametro =~ m/^ses_delay\s(.*)/i) { + $config->{'ses_delay'} = $1; + } + elsif ($parametro =~ m/^con_delay\s(.*)/i) { + $config->{'con_delay'} = $1; + } + elsif ($parametro =~ m/^agent\s(.*)/i) { + $config->{'agent'} = $1; + } + elsif ($parametro =~ m/^proxy\s(.*)/i) { + $config->{'proxy'} = $1; + } + elsif ($parametro =~ m/^max_depth\s(.*)/i) { + $config->{'max_depth'} = $1; + } + elsif ($parametro =~ m/^log_file\s(.*)/i) { + $config->{"log_file"} = $1; + } + elsif ($parametro =~ m/^log_output\s(.*)/i) { + $config->{"log_output"} = $1; + } + elsif ($parametro =~ m/^log_http\s(.*)/i) { + $config->{"log_http"} = $1; + } + elsif ($parametro =~ m/^retries\s(.*)/i) { + $config->{"retries"} = $1; + } + # ~~~~~~~~~~~~~~ + # Task items + # ~~~~~~~~~~~~~~ + elsif ($parametro =~ m/^variable_name\s(.*)/i) { + push (@task_variable_name, $1); + } + elsif ($parametro =~ m/^variable_value\s(.*)/i) { + push (@task_variable_value, $1); + } + elsif ($parametro =~ m/^check_string\s(.*)/i) { + push (@task_check_string, $1); + } + elsif ($parametro =~ m/^check_not_string\s(.*)/i) { + push (@task_check_not_string, $1); + } + elsif ($parametro =~ m/^get\s(.*)/i) { + $task_type = "GET"; + $task_url = $1; + } + elsif ($parametro =~ m/^post\s(.*)/i) { + $task_type = "POST"; + $task_url = $1; + } + elsif ($parametro =~ m/^head\s(.*)/i) { + $task_type = "HEAD"; + $task_url = $1; + } + # New in 4.0 version + elsif ($parametro =~ m/^get_string\s(.*)/i) { + $get_string = $1; + } + elsif ($parametro =~ m/^get_content\s(.*)/i) { + $get_content = $1; + } + elsif ($parametro =~ m/^get_content_advanced\s(.*)/i) { + $get_content_advanced = $1; + } + elsif ($parametro =~ m/^http_auth_user\s(.*)/i) { + $http_auth_user = $1; + } + elsif ($parametro =~ m/^http_auth_pass\s(.*)/i) { + $http_auth_pass = $1; + } + elsif ($parametro =~ m/^http_auth_realm\s(.*)/i) { + $http_auth_realm = $1; + } + elsif ($parametro =~ m/^http_auth_serverport\s(.*)/i) { + $http_auth_serverport = $1; + } + elsif ($parametro =~ m/^cookie\s(.*)/i) { + if ($1 =~ m/1/i){ + $task_cookie = 1; + } else { + $task_cookie = 0; + } + } + elsif ($parametro =~ m/^resource\s(.*)/i) { + if ($1 =~ m/1/i){ + $task_resources = 1; + } else { + $task_resources = 0; + } + } + # New in 5.0 version + elsif ($parametro =~ m/^header\s+(\S+)\s(.*)/i) { + $task_headers->{$1} = $2; + } + elsif ($parametro =~ m/^debug\s+(.*)/i) { + $task_debug = $1; + } + + } + close (CFG); +} + +# End of function declaration +# End of defined Code + +1; +__END__ + + diff --git a/pandora_server/lib/PandoraFMS/Goliat/GoliatLWP.pm b/pandora_server/lib/PandoraFMS/Goliat/GoliatLWP.pm new file mode 100755 index 0000000000..3117ab1515 --- /dev/null +++ b/pandora_server/lib/PandoraFMS/Goliat/GoliatLWP.pm @@ -0,0 +1,478 @@ +################################################################################## +# Goliath Tools LWP Module +################################################################################## +# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L +# This code is not free or OpenSource. Please don't redistribute. +################################################################################## + +package PandoraFMS::Goliat::GoliatLWP; + +use PandoraFMS::Goliat::GoliatTools; + +use strict; +use warnings; +use Data::Dumper; + +use IO::Socket::INET6; +use LWP::UserAgent; +use LWP::ConnCache; +use HTTP::Request::Common; +use HTTP::Response; +use HTML::TreeBuilder; +use HTML::Element; +use HTTP::Cookies; +use URI::URL; +use Time::Local; +use Time::HiRes qw ( gettimeofday ); + +# For IPv6 support in Net::HTTP. +BEGIN { + $Net::HTTP::SOCKET_CLASS = 'IO::Socket::INET6'; + require Net::HTTP; +} + +# Japanese encoding support +use Encode::Guess qw/euc-jp shiftjis iso-2022-jp/; + +require Exporter; + +our @ISA = ("Exporter"); +our %EXPORT_TAGS = ( 'all' => [ qw() ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = qw( + g_http_task + @task_requests + @task_reqsec + @task_fails + @task_time + @task_end + @task_sessions + @task_ssec + @task_get_string + @task_get_content + @task_session_fails +); + +our @task_requests; +our @task_reqsec; +our @task_fails; +our @task_time; +our @task_end; +our @task_sessions; +our @task_ssec; +our @task_get_string; +our @task_get_content; +our @task_session_fails; +our $goliat_abort; + +sub parse_html ($;$) +{ + my $p = $_[1]; + $p = _new_tree_maker() unless $p; + $p->parse($_[0]); +} + + +sub parse_htmlfile ($;$) +{ + my($file, $p) = @_; + local(*HTML); + open(HTML, $file) or return undef; + $p = _new_tree_maker() unless $p; + $p->parse_file(\*HTML); +} + +sub _new_tree_maker +{ + my $p = HTML::TreeBuilder->new(implicit_tags => 1, + ignore_unknown => 1, + ignore_text => 0, + 'warn' => 0, + ); + $p->strict_comment(1); + $p; +} + + +sub g_http_task { + my ( $config, $thread_id, @work_list ) = @_; + my ( $ax, $bx, $cx ); # used in FOR loop + my ( $ttime1, $ttime2, $ttime_tot ); + + my $resp; # HTTP Response + my $total_requests = 0; + my $total_valid_requests = 0; + my $total_invalid_request = 0; + my $cookie_file = "/tmp/gtc_".$thread_id."_".g_trash_ascii (3); + my $check_string = 1; + my $get_string = ""; + my $get_content = ""; + my $get_content_advanced = ""; + + my $ua = new LWP::UserAgent; + $task_requests [$thread_id] = 0 ; + $task_sessions [$thread_id] = 0 ; + $task_reqsec[$thread_id] = 0; + $task_fails[$thread_id] = 0; + $task_session_fails[$thread_id] = 0; + $task_ssec[$thread_id] = 0; + $task_end[$thread_id] = 0; + $task_time[$thread_id] = 0; + $task_get_string[$thread_id] = ""; + $task_get_content[$thread_id] = ""; + + $ua->agent($config->{"agent"}); + $ua->protocols_allowed( ['http', 'https'] ); + $ua->default_headers->push_header('pragma' => "no-cache"); + $ua->timeout ($config->{"timeout"}); + $ua->max_size($config->{"maxsize"}); + $ua->use_alarm($config->{"alarm"}); + + # Disable SSL certificate host verification + if ($ua->can ('ssl_opts')) { + $ua->ssl_opts("verify_hostname" => 0); + } + + # Set proxy + + if ($config->{'proxy'} ne ""){ + $ua->proxy(['http','https'], $config->{'proxy'}); + } + + # Set HTTP Proxy auth + if ($config->{'auth_user'} ne "") { + $ua->credentials( + $config->{'auth_server'}, + $config->{'auth_realm'}, + $config->{'auth_user'} => $config->{'auth_pass'} ); + } + + if ( -e $cookie_file){ + unlink ($cookie_file); + } + my $cookies = HTTP::Cookies->new ('file' => $cookie_file, 'autosave' => '0'); + + $ttime1 = Time::HiRes::gettimeofday(); + for ($ax = 0; $ax != $config->{'retries'}; $ax++){ + for ($bx = 0; $bx < $config->{"work_items"}; $bx++){ + if ($config->{'con_delay'} > 0){ + sleep ($config->{'con_delay'}); + } + $total_requests++; + # Start to count! + $check_string = 1; + # Prepare parameters + my $params = ""; + $cx = 0; + while (defined($work_list[$bx]->{'variable_name'}[$cx])){ + if ($cx > 0){ + $params = $params."&"; + } + $params = $params . $work_list[$bx]->{'variable_name'}[$cx] . "=" . $work_list[$bx]->{'variable_value'}[$cx]; + $cx++; + } + + if ( (defined($work_list[$bx]->{'http_auth_realm'})) && (defined($work_list[$bx]->{'http_auth_serverport'}))&& (defined($work_list[$bx]->{'http_auth_user'})) && (defined($work_list[$bx]->{'http_auth_pass'}))) { + if ($work_list[$bx]->{'http_auth_realm'} ne "") { + $ua->credentials( + $work_list[$bx]->{'http_auth_serverport'}, + $work_list[$bx]->{'http_auth_realm'}, + $work_list[$bx]->{'http_auth_user'} => $work_list[$bx]->{'http_auth_pass'} + ); + } + } + + # GET + if ($work_list[$bx]->{'type'} eq "GET"){ + if ($cx > 0){ + $params = $work_list[$bx]->{'url'} . "?" . $params; + } else { + $params = $work_list[$bx]->{'url'}; + } + $resp = g_get_page ( $ua, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}); + + # POST + } elsif ($work_list[$bx]->{'type'} eq "POST") { + $resp = g_post_page ( $ua, $work_list[$bx]->{'url'}, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}); + + # HEAD + } else { + if ($cx > 0){ + $params = $work_list[$bx]->{'url'} . "?" . $params; + } else { + $params = $work_list[$bx]->{'url'}; + } + $resp = g_head_page ( $ua, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}); + } + + # Check for errors. + if ($resp->code() == 500) { + $total_invalid_request++; + $bx = $config->{"work_items"}; + $check_string=0; + last; + } + + # Get string ? + if (defined($work_list[$bx]->{'get_string'})) { + my $as_string = $resp->as_string; + my $temp = $work_list[$bx]->{'get_string'}; + if ($as_string =~ m/($temp)/) { + $task_get_string[$thread_id] = $1; + } + } + + # Get response ? + if ($work_list[$bx]->{'get_content_advanced'} ne "") { + my $content = $resp->decoded_content; + my $temp = $work_list[$bx]->{'get_content_advanced'}; + if ($content =~ m/$temp/) { + $task_get_content[$thread_id] = $1 if defined ($1); + } + } elsif ($work_list[$bx]->{'get_content'} ne "") { + my $content = $resp->decoded_content; + my $temp = $work_list[$bx]->{'get_content'}; + if ($content =~ m/($temp)/) { + $task_get_content[$thread_id] = $1; + } + } + + # Resource bashing + if ((defined($work_list[$bx]->{'get_resources'})) && ($work_list[$bx]->{'get_resources'} == 1)){ + $total_requests = g_get_all_links ($config, $ua, $resp, $total_requests, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}); + } + + # CHECKSTRING check + $cx = 0; + while (defined($work_list[$bx]->{'checkstring'}[$cx])) { + my $match_string = $work_list[$bx]->{'checkstring'}[$cx]; + my $as_string = $resp->as_string; + + my $guess = Encode::Guess::guess_encoding($as_string); + if (ref $guess) { + $as_string = $guess->decode($as_string); + } + unless (utf8::is_utf8($match_string)) { + utf8::decode($match_string); + } + + if ( $as_string =~ m/$match_string/i ){ + $total_valid_requests++; + } else { + $total_invalid_request++; + $bx = $config->{"work_items"}; # Abort session remaining request + $check_string=0; + } + $cx++; + } + + # CHECKNOTSTRING check + $cx = 0; + while (defined($work_list[$bx]->{'checknotstring'}[$cx])) { + my $match_string = $work_list[$bx]->{'checknotstring'}[$cx]; + my $as_string = $resp->as_string; + + my $guess = Encode::Guess::guess_encoding($as_string); + if (ref $guess) { + $as_string = $guess->decode($as_string); + } + unless (utf8::is_utf8($match_string)) { + utf8::decode($match_string); + } + + if ( $as_string !~ m/$match_string/i ){ + $total_valid_requests++; + } else { + $total_invalid_request++; + $bx = $config->{"work_items"}; # Abort session remaining request + $check_string=0; + } + $cx++; + } + + # Cookie carry on + if (defined ($work_list[$bx]->{'cookie'}) && $work_list[$bx]->{'cookie'} == 1){ + $cookies->extract_cookies($resp); + $ua->cookie_jar($cookies); + } + + # End just now by pressing CTRL-C or Kill Signal ! + #if ($goliat_abort == 1){ + #$ax = $config->{'retries'}; + #$bx = $config->{'items'}; + #goto END_LOOP; + #} + } #main work_detail loop + $ttime2 = Time::HiRes::gettimeofday(); + + $ttime_tot = $ttime2 - $ttime1; # Total time for this task + $task_time[$thread_id] = $ttime_tot; + $task_requests [$thread_id] = $total_requests; + if ($ttime_tot > 0 ){ + $task_reqsec[$thread_id] = $total_requests / $ttime_tot; + } else { + $task_reqsec[$thread_id] = $total_requests; + } + $task_fails[$thread_id] = $total_invalid_request; + if ($check_string == 0){ + $task_session_fails[$thread_id]++ + } + $task_sessions [$thread_id]++; + if ($task_sessions [$thread_id] > 0 ){ + $task_ssec[$thread_id] = $ttime_tot / $task_sessions [$thread_id]; + } else { + $task_ssec[$thread_id] = $task_sessions[$thread_id]; + } + sleep $config->{'ses_delay'}; + } +END_LOOP: + + $cookies->clear; + + if ( -f $cookie_file){ + unlink ($cookie_file); + } + + $task_end[$thread_id] = 1; +} + + +sub g_get_all_links { + my ($config, $ua, $response, $counter, $myurl, $headers, $debug) = @_; + my $html; + + if ($response->is_success) { + $html = $response->content; + } else { + return $counter; + } + # Beware this funcion, needs to be destroyed after use it !!! + my $parsed_html = parse_html($html); + #$ua->conn_cache(LWP::ConnCache->new()); + + my @url_list; + my $url = ""; + my $link; + my $full_url; + + for (@{ $parsed_html->extract_links( ) }) { + $link=$_->[0]; + if (($link =~ m/.png/i) || ($link =~ m/.gif/i) || ($link =~ m/.htm/i) || + ($link =~ m/.html/i) || ($link =~ m/.pdf/i) || ($link =~ m/.jpg/i) + || ($link =~ m/.ico/i)){ + $url = new URI::URL $link; + $full_url = $url->abs($myurl); + @url_list = $full_url; + } + + } + $parsed_html->delete; + my $ax = 0; + while ($full_url = pop(@url_list)) { + g_get_page ($ua, $full_url, $headers, $debug); + $counter++; + $ax++; + if ($ax > $config->{"max_depth"}){ + return $counter; + } + } + return $counter; +} + +sub g_get_page { + my $ua = $_[0]; + my $url = $_[1]; + my $headers = $_[2]; + my $debug = $_[3]; + + my $req = HTTP::Request->new(GET => $url); + $req->header('Accept' => 'text/html'); + while (my ($header, $value) = each %{$headers}) { + $req->header($header => $value); + } + my $response = $ua->request($req); + return $response if ($debug eq ''); + + # Debug + if (open (DEBUG, '>>', $debug . '.req')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $req->as_string (); + print "\n"; + close (DEBUG); + } + if (open (DEBUG, '>>', $debug . '.res')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $response->as_string (); + print "\n"; + close (DEBUG); + } + return $response; +} + +sub g_head_page { + my $ua = $_[0]; + my $url = $_[1]; + my $headers = $_[2]; + my $debug = $_[3]; + + my $req = HTTP::Request->new(HEAD => $url); + $req->header('Accept' => 'text/html'); + while (my ($header, $value) = each %{$headers}) { + $req->header($header => $value); + } + my $response = $ua->request($req); + return $response if ($debug eq ''); + + # Debug + if (open (DEBUG, '>>', $debug . '.req')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $req->as_string (); + print "\n"; + close (DEBUG); + } + if (open (DEBUG, '>>', $debug . '.res')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $response->as_string (); + print "\n"; + close (DEBUG); + } + return $response; +} + +sub g_post_page { + my $ua = $_[0]; + my $url = $_[1]; + my $content = $_[2]; + my $headers = $_[3]; + my $debug = $_[4]; + + my $req = HTTP::Request->new(POST => $url); + $req->content_type('application/x-www-form-urlencoded'); + $req->content ($content); + while (my ($header, $value) = each %{$headers}) { + $req->header($header => $value); + } + my $response = $ua->request($req); + return $response if ($debug eq ''); + + # Debug + if (open (DEBUG, '>>', $debug . '.req')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $req->as_string (); + print "\n"; + close (DEBUG); + } + if (open (DEBUG, '>>', $debug . '.res')) { + print DEBUG "[Goliat debug " . time () . "]\n"; + print DEBUG $response->as_string (); + print "\n"; + close (DEBUG); + } + return $response; +} + +# End of function declaration +# End of defined Code + +1; +__END__ diff --git a/pandora_server/lib/PandoraFMS/Goliat/GoliatTools.pm b/pandora_server/lib/PandoraFMS/Goliat/GoliatTools.pm new file mode 100755 index 0000000000..2c320477dc --- /dev/null +++ b/pandora_server/lib/PandoraFMS/Goliat/GoliatTools.pm @@ -0,0 +1,222 @@ +############################################################################### +# Goliath Tools Module +############################################################################### +# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L +# This code is not free or OpenSource. Please don't redistribute. +############################################################################### + +package PandoraFMS::Goliat::GoliatTools; + +use 5.008004; +use strict; +use warnings; +use integer; + +require Exporter; + +our @ISA = ("Exporter"); +our %EXPORT_TAGS = ( 'all' => [ qw() ] ); +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); +our @EXPORT = qw( + g_clean_string + g_clean_string_unicode + g_random_string + g_trash_ascii + g_trash_unicode + g_unicode ); + +# Delaracion de funciones publicas + +############################################################################## +# clean_string (string) - Purge a string for any forbidden characters (esc, etc) +############################################################################## +sub g_clean_string { + my $micadena; + $micadena = $_[0]; + $micadena =~ s/[^\-\:\;\.\,\_\s\a\*\=\(\)a-zA-Z0-9]/ /g; + $micadena =~ s/[\n\l\f]/ /g; + return $micadena; +} + +############################################################################## +# limpia_cadena_unicode (string) - Purge a string for any unicode character +############################################################################## +sub g_clean_string_unicode { + my $micadena; + $micadena = $_[0]; + $micadena =~ s/[%]/%%/g; + return $micadena; +} + +############################################################################# +# Hex converter - Convert dec value in hex representation (00 - FF) +############################################################################# +sub g_decToHex { #return a 16bit (o uno de 8bit) hex value + my @hex = (0,1,2,3,4,5,6,7,8,9,"A","B","C","D","E","F"); + my @dec = @_; + my $s3 = $hex[($dec[0]/4096)%16]; + my $s2 = $hex[($dec[0]/256)%16]; + my $s1 = $hex[($dec[0]/16)%16]; + my $s0 = $hex[$dec[0]%16]; + return "$s1$s0"; +} + +############################################################################# +# unicode - Generate unicode string (recursive) +############################################################################# + +sub g_unicode { + my $config_word = $_[0]; + my $config_depth = $_[1]; + my $config_char="%"; + if ($config_depth == 0) { + return $config_word; + } + + my $a; + my $pos=0; + my $output=""; + my $len; + + for ($a=0;$a<$config_depth;$a++){ + $len = length($config_word); + while ($pos < $len ) { + my $item; + $item = substr($config_word,$pos,1); + $output = $output.$config_char.decToHex(ord($item)); + $pos++; + } + $config_word = $output; + } + return $output +} + +############################################################################# +# trash - Generate "unicode" style trash string +############################################################################# + +sub g_trash_unicode { + my $config_depth = $_[0]; + my $config_char="%"; + my $a; + my $output; + + for ($a=0;$a<$config_depth;$a++){ + $output = $output.$config_char.decToHex(int(rand(25)+97)); + } + return $output +} + +############################################################################# +# trash_ascii - Generate ASCII random strings +############################################################################# + +sub g_trash_ascii { + my $config_depth = $_[0]; + my $config_char="%"; + my $a; + my $output; + + for ($a=0;$a<$config_depth;$a++){ + $output = $output.chr(int(rand(25)+97)); + } + return $output +} + +############################################################################# +# random_string (min, max, type) - Generate ASCII alphanumeric string, +# from min and max +############################################################################# + +sub g_random_string { + my $config_min = $_[0]; + my $config_max = $_[1]; + my $config_type = $_[2]; # alphanumeric, alpha, numeric, lowalpha, highalpha + my $a; + my $output = ""; + my @valid_chars; + my $rango; + + # First fill list of valid chars (A-Z, a-z, 0-9) + if (($config_type eq "alphanumeric") || ($config_type eq "numeric")){ + for ($a=48;$a<58;$a++){ # numeric + push @valid_chars, chr($a); + } + } + + if (($config_type eq "alphanumeric") || ($config_type eq "alpha") || + ($config_type eq "highalpha") || ($config_type eq "lowalpha") ){ + if (($config_type eq "alphanumeric") || ($config_type eq "highalpha") || ($config_type eq "alpha")){ + for ($a=65;$a<91;$a++){ # alpha (CAPS) + push @valid_chars, chr($a); + } + } + if (($config_type eq "alphanumeric") || ($config_type eq "lowalpha") || ($config_type eq "alpha")){ + for ($a=97;$a<123;$a++){ # alpha (low) + push @valid_chars, chr($a); + } + } + } + + $rango = @valid_chars; + + # Fill min. value + for ($a=0;$a<$config_min;$a++){ + $output = $output.$valid_chars[(int(rand($rango)))]; + } + + # Fill to max; + if (($config_max - $config_min) != 0){ + for ($a=0;$aslerena@Egmail.com + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2005 by Sancho Lerena + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.8.4 or, +at your option, any later version of Perl 5 you may have available. + +Licenced under GPL + +=cut diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 22b79fa286..4e20c5e69f 100644 --- a/pandora_server/lib/PandoraFMS/PluginTools.pm +++ b/pandora_server/lib/PandoraFMS/PluginTools.pm @@ -34,7 +34,7 @@ our @ISA = qw(Exporter); # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.754"; -my $pandora_build = "210512"; +my $pandora_build = "210513"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/lib/PandoraFMS/WebServer.pm b/pandora_server/lib/PandoraFMS/WebServer.pm new file mode 100644 index 0000000000..b900c21fb9 --- /dev/null +++ b/pandora_server/lib/PandoraFMS/WebServer.pm @@ -0,0 +1,304 @@ +package PandoraFMS::WebServer; +########################################################################## +# Pandora FMS Web Server. +# Pandora FMS. the Flexible Monitoring System. http://www.pandorafms.org +########################################################################## +# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation; version 2 +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +########################################################################## + +use strict; +use warnings; + +use threads; +use threads::shared; +use Thread::Semaphore; + +use File::Temp qw(tempfile); +use HTML::Entities; +use POSIX qw(strftime); + +# Default lib dir for RPM and DEB packages +use lib '/usr/lib/perl5'; + +use PandoraFMS::Tools; +use PandoraFMS::DB; +use PandoraFMS::Core; +use PandoraFMS::ProducerConsumerServer; + +use PandoraFMS::Goliat::GoliatTools; +use PandoraFMS::Goliat::GoliatConfig; + +# Inherits from PandoraFMS::ProducerConsumerServer +our @ISA = qw(PandoraFMS::ProducerConsumerServer); + +# Global variables +my @TaskQueue :shared; +my %PendingTasks :shared; +my $Sem :shared; +my $TaskSem :shared; + +######################################################################################## +# Web Server class constructor. +######################################################################################## +sub new ($$;$) { + my ($class, $config, $dbh) = @_; + + return undef unless defined ($config->{'webserver'}) and ($config->{'webserver'} == 1); + + # Initialize semaphores and queues + @TaskQueue = (); + %PendingTasks = (); + $Sem = Thread::Semaphore->new; + $TaskSem = Thread::Semaphore->new (0); + + # Call the constructor of the parent class + my $self = $class->SUPER::new($config, WEBSERVER, \&PandoraFMS::WebServer::data_producer, \&PandoraFMS::WebServer::data_consumer, $dbh); + + bless $self, $class; + return $self; +} + +############################################################################### +# Run. +############################################################################### +sub run ($) { + my $self = shift; + my $pa_config = $self->getConfig (); + + print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Web Server.", 1); + + # Use Goliat with CURL + if ($pa_config->{'web_engine'} eq 'curl') { + require PandoraFMS::Goliat::GoliatCURL; + PandoraFMS::Goliat::GoliatCURL->import; + + # Check for CURL binary + if (system ("curl -V >$DEVNULL 2>&1") >> 8 != 0) { + logger ($pa_config, ' [E] CURL binary not found. Install CURL or uncomment the web_engine configuration token to use LWP.', 1); + print_message ($pa_config, ' [E] CURL binary not found. Install CURL or uncomment the web_engine configuration token to use LWP.', 1); + return undef; + } + # Check for pandora_exec binary + if (system ("\"" . $pa_config->{'plugin_exec'} . "\" 10 echo >$DEVNULL 2>&1") >> 8 != 0) { + logger ($pa_config, ' [E] ' . $pa_config->{'plugin_exec'} . ' not found. Please install it or add it to the PATH.', 1); + print_message ($pa_config, ' [E] ' . $pa_config->{'plugin_exec'} . ' not found. Please install it or add it to the PATH.', 1); + return undef; + } + } + # Use LWP by default + else { + require PandoraFMS::Goliat::GoliatLWP; + PandoraFMS::Goliat::GoliatLWP->import; + + if (! LWP::UserAgent->can('ssl_opts')) { + logger($pa_config, "LWP version $LWP::VERSION does not support SSL. Make sure version 6.0 or higher is installed.", 1); + print_message ($pa_config, " [W] LWP version $LWP::VERSION does not support SSL. Make sure version 6.0 or higher is installed.", 1); + } + } + + $self->setNumThreads ($pa_config->{'web_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 @rows; + + if (pandora_is_master($pa_config) == 0) { + @rows = get_db_rows ($dbh, 'SELECT tagente_modulo.id_agente_modulo, tagente_modulo.flag, tagente_estado.current_interval + tagente_estado.last_execution_try AS time_left, last_execution_try + FROM tagente, tagente_modulo, tagente_estado + WHERE server_name = ? + AND tagente_modulo.id_agente = tagente.id_agente + AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo + AND tagente.disabled = 0 + AND tagente_modulo.id_modulo = 7 + AND tagente_modulo.disabled = 0 + AND (tagente_modulo.flag = 1 OR ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP())) + ORDER BY tagente_modulo.flag DESC, time_left ASC, last_execution_try ASC ', $pa_config->{'servername'}); + } else { + @rows = get_db_rows ($dbh, 'SELECT DISTINCT(tagente_modulo.id_agente_modulo), tagente_modulo.flag, tagente_estado.current_interval + tagente_estado.last_execution_try AS time_left, last_execution_try + FROM tagente, tagente_modulo, tagente_estado, tserver + WHERE ((server_name = ?) OR (server_name = ANY(SELECT server_name FROM tserver WHERE status = 0 AND server_type = ?))) + AND tagente_modulo.id_agente = tagente.id_agente + AND tagente.disabled = 0 + AND tagente_modulo.disabled = 0 + AND tagente_modulo.id_modulo = 7 + AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo + AND ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 ) + ORDER BY tagente_modulo.flag DESC, time_left ASC, last_execution_try ASC', $pa_config->{'servername'}, WEBSERVER); + } + + foreach my $row (@rows) { + + # Reset forced execution flag + if ($row->{'flag'} == 1) { + db_do ($dbh, 'UPDATE tagente_modulo SET flag = 0 WHERE id_agente_modulo = ?', $row->{'id_agente_modulo'}); + } + + push (@tasks, $row->{'id_agente_modulo'}); + } + + return @tasks; +} + +############################################################################### +# Data consumer. +############################################################################### +sub data_consumer ($$) { + my ($self, $module_id) = @_; + my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ()); + our (@task_fails, @task_time, @task_ssec, @task_get_content); # Defined in GoliatLWP.pm and GoliatCURL. + + # Retrieve module data + my $module = get_db_single_row ($dbh, 'SELECT * FROM tagente_modulo WHERE id_agente_modulo = ?', $module_id); + return unless defined ($module); + + # Retrieve agent data + my $agent = get_db_single_row ($dbh, 'SELECT * FROM tagente WHERE id_agente = ?', $module->{'id_agente'}); + return unless defined $agent; + + # Save Goliat config to a temporary file + my ($fh, $temp_file) = tempfile(); + return unless defined ($fh); + + # Read the Goliat task + my $task = safe_output($module->{'plugin_parameter'}); + + # Delete any carriage returns + $task =~ s/\r//g; + + # Agent and module macros + my %macros = (_agent_ => (defined ($agent)) ? $agent->{'alias'} : '', + _agentdescription_ => (defined ($agent)) ? $agent->{'comentarios'} : '', + _agentstatus_ => (defined ($agent)) ? get_agent_status ($pa_config, $dbh, $agent->{'id_agente'}) : '', + _address_ => (defined ($agent)) ? $agent->{'direccion'} : '', + _module_ => (defined ($module)) ? $module->{'nombre'} : '', + _modulegroup_ => (defined ($module)) ? (get_module_group_name ($dbh, $module->{'id_module_group'}) || '') : '', + _moduledescription_ => (defined ($module)) ? $module->{'descripcion'} : '', + _modulestatus_ => (defined ($module)) ? get_agentmodule_status($pa_config, $dbh, $module->{'id_agente_modulo'}) : '', + _moduletags_ => (defined ($module)) ? pandora_get_module_url_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '', + _id_agent_ => (defined ($module)) ? $module->{'id_agente'} : '', + _interval_ => (defined ($module) && $module->{'module_interval'} != 0) ? $module->{'module_interval'} : (defined ($agent)) ? $agent->{'intervalo'} : '', + _target_ip_ => (defined ($agent)) ? $agent->{'direccion'} : '', + _target_port_ => (defined ($module)) ? $module->{'tcp_port'} : '', + _policy_ => (defined ($module)) ? enterprise_hook('get_policy_name', [$dbh, $module->{'id_policy_module'}]) : '', + _plugin_parameters_ => (defined ($module)) ? $module->{'plugin_parameter'} : '', + _email_tag_ => (defined ($module)) ? pandora_get_module_email_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '', + _phone_tag_ => (defined ($module)) ? pandora_get_module_phone_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '', + _name_tag_ => (defined ($module)) ? pandora_get_module_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '', + ); + $task = subst_alert_macros ($task, \%macros); + + # Goliat has some trouble parsing conf files without the newlines + $fh->print ("\n\n" . $task . "\n\n"); + close ($fh); + + # Global vars needed by Goliat + my (%config, @work_list, $check_string); + + # Goliat config defaults + $config{'verbosity'} = 1; + $config{'slave'} = 0; + $config{'port'} = 80; + $config{'log_file'} = "$DEVNULL"; + $config{'log_output'} = 0; + $config{'log_http'} = 0; + $config{'work_items'} = 0; + $config{'config_file'} = $temp_file; + $config{'agent'} = safe_output($module->{'plugin_user'}); + if ($module->{'max_retries'} != 0) { + $config{'retries'} = $module->{'max_retries'}; + } + if ($module->{'max_timeout'} != 0) { + $config{'timeout'} = $module->{'max_timeout'}; + } else { + $config{'timeout'} = $pa_config->{'web_timeout'}; + } + + $config{'proxy'} = $module->{'snmp_oid'}; + $config{'auth_user'} = safe_output($module->{'tcp_send'}); + $config{'auth_pass'} = safe_output($module->{'tcp_rcv'}); + $config{'auth_server'} = $module->{'ip_target'}; + $config{'auth_realm'} = $module->{'snmp_community'}; + $config{'http_check_type'} = $module->{'tcp_port'}; + $config{'moduleId'} = $module_id; + $config{'dbh'} = $dbh; + + # Pandora FMS variables passed to Goliat. + $config{'plugin_exec'} = $pa_config->{'plugin_exec'}; + + eval { + # Load Goliat config + g_load_config(\%config, \@work_list); + + # Run Goliat task + g_http_task (\%config, 0, @work_list); + }; + + if ($@) { + pandora_update_module_on_error ($pa_config, $module, $dbh); + unlink ($temp_file); + return; + } + + unlink ($temp_file); + + my $utimestamp = time (); + my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp)); + + # Get module type + my $module_type = get_db_value ($dbh, 'SELECT nombre FROM ttipo_modulo WHERE id_tipo = ?', $module->{'id_tipo_modulo'}); + + # Get data from Goliat + my $module_data; + { + no strict 'vars'; + if ($module_type eq 'web_proc') { + $module_data = ($task_fails[0] == 0 && $task_get_content[0] ne "") ? 1 : 0; + } + elsif ($module_type eq 'web_data') { + $module_data = $task_ssec[0]; + } elsif ($module_type eq 'web_server_status_code_string') { + my @resp_lines = split "\r\n", $task_get_content[0]; + $module_data = $resp_lines[0]; + } else { + $module_data = $task_get_content[0]; + } + } + + my %data = ("data" => $module_data); + pandora_process_module ($pa_config, \%data, undef, $module, $module_type, $timestamp, $utimestamp, $self->getServerID (), $dbh); + + my $agent_os_version = get_db_value ($dbh, 'SELECT os_version FROM tagente WHERE id_agente = ?', $module->{'id_agente'}); + + if (! defined ($agent_os_version) || $agent_os_version eq '') { + $agent_os_version = $pa_config->{'servername'}.'_Web'; + } + + # Todo: Implement here + # 1. Detect if exists a module with the same name, but with type generic_string. + # 2. If not, create the module, get the id's + # 3. Insert data coming from $task_get_string in that module + + pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh); +} + +1; +__END__ diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index d19af75b60..8a8cfd64fa 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.754 -%define release 210512 +%define release 210513 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index ec3596edb0..36504c200e 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.754 -%define release 210512 +%define release 210513 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index a5890a25d9..34be4a360a 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.754" -PI_BUILD="210512" +PI_BUILD="210513" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index ae17729999..83a9dfdec9 100755 --- 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.754 PS210512"; +my $version = "7.0NG.754 Build 210513"; # Pandora server configuration my %conf; @@ -548,7 +548,7 @@ sub pandora_compactdb ($$$) { sub pandora_init_pdb ($) { my $conf = shift; - log_message ('', "\nDB Tool $version Copyright (c) 2004-2018 " . pandora_get_initial_copyright_notice() . "\n"); + log_message ('', "Pandora FMS DB Tool v$version\n\n"); log_message ('', "This program is Free Software, licensed under the terms of GPL License v2\n"); log_message ('', "You can download latest versions and documentation at official web\n\n"); diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index fa47a00410..0d8a97ae19 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.754 PS210512"; +my $version = "7.0NG.754 Build 210513"; # save program name for logging my $progname = basename($0);