diff --git a/extras/docker/centos8/docker-compose.yml b/extras/docker/centos8/docker-compose.yml index f33b6fe9ed..5ac5385133 100644 --- a/extras/docker/centos8/docker-compose.yml +++ b/extras/docker/centos8/docker-compose.yml @@ -17,7 +17,7 @@ services: - pandora pandora: - image: pandorafms/pandorafms-open-stack-el8:749 + image: pandorafms/pandorafms-open-stack-el8:latest restart: always depends_on: - db diff --git a/extras/pandora_update_version.sh b/extras/pandora_update_version.sh index 8a16e8e18d..23ea7a4627 100755 --- a/extras/pandora_update_version.sh +++ b/extras/pandora_update_version.sh @@ -143,7 +143,7 @@ done # Darwin dmg installer files echo "Updating DARWIN DMG files..." -sed -i -e "/VERSION/s/=.*/=\"$VERSION\"/" "$AGENT_DARWIN_BUILDER" +sed -i -e "/VERSION/s/=\"7.0NG.*/=\"$VERSION\"/" "$AGENT_DARWIN_BUILDER" sed -i -r "s/(version=\").*(\"\s+onConclusion=)/\1$VERSION\2/g" "$AGENT_DARWIN_DISTR" sed -i -r "s/(CFBundleVersion<\/key>\s*<string>).*(<\/string>)/\1$VERSION\2/g" "$AGENT_DARWIN_PLIST" sed -i -r "s/(CFBundleShortVersionString<\/key>\s*<string>).*(<\/string>)/\1$VERSION\2/g" "$AGENT_DARWIN_PLIST" diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index bb54c56b4c..c8eea02fb7 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.750-201029 +Version: 7.0NG.750-201123 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 7e6e85035c..5e440bdeac 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.750-201029" +pandora_version="7.0NG.750-201123" 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/Darwin/dmg/build_darwin_dmg.sh b/pandora_agents/unix/Darwin/dmg/build_darwin_dmg.sh index 325d149578..95878467ab 100644 --- a/pandora_agents/unix/Darwin/dmg/build_darwin_dmg.sh +++ b/pandora_agents/unix/Darwin/dmg/build_darwin_dmg.sh @@ -22,7 +22,7 @@ fi # DMG package version if [ "$#" -ge 2 ]; then - VERSION="7.0NG.750" + VERSION="$2" else VERSION="7.0NG.750" fi @@ -37,7 +37,7 @@ fi BUILD_DMG="$BUILD_PATH/build" BUILD_TMP="$BUILD_PATH/buildtmp" -FULLNAME="7.0NG.749" +FULLNAME="$DMGNAME-$VERSION.dmg" echo "VERSION-"$VERSION" NAME-"$DMGNAME pushd . cd $LOCALINST diff --git a/pandora_agents/unix/Darwin/dmg/scripts/postinstall b/pandora_agents/unix/Darwin/dmg/scripts/postinstall index 2f76310fee..5b25222a37 100644 --- a/pandora_agents/unix/Darwin/dmg/scripts/postinstall +++ b/pandora_agents/unix/Darwin/dmg/scripts/postinstall @@ -26,11 +26,13 @@ else `/usr/local/share/pandora_agent/inst_utilities/print_conf.pl /usr/local/share/pandora_agent/pandora_agent.conf remote_config $REMOTECFG` # Create agent directories and files - mkdir -p /usr/local/share/pandora_agent/collections - mkdir -p /usr/local/share/pandora_agent/commands + mkdir -p /usr/local/bin/ + mkdir -p /usr/local/share/man/man1/ + mkdir -p /usr/local/share/pandora_agent/collections/ + mkdir -p /usr/local/share/pandora_agent/commands/ mkdir -p /etc/pandora/ - mkdir -p /var/spool/pandora/data_out - mkdir -p /var/log/pandora + mkdir -p /var/spool/pandora/data_out/ + mkdir -p /var/log/pandora/ mv pandora_agent.conf /etc/pandora/ touch /var/log/pandora/pandora_agent.log @@ -70,9 +72,9 @@ ln -s /usr/local/share/pandora_agent/collections /etc/pandora/collections # Copy manuals -cp -f man/man1/pandora_agent.1.gz /usr/local/share/man/man1 +cp -f man/man1/pandora_agent.1.gz /usr/local/share/man/man1/ chmod 644 /usr/local/share/man/man1/pandora_agent.1.gz -cp -f man/man1/tentacle_client.1.gz /usr/local/share/man/man1 +cp -f man/man1/tentacle_client.1.gz /usr/local/share/man/man1/ chmod 644 /usr/local/share/man/man1/tentacle_client.1.gz # Create newsyslog entry diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index d55e379f01..e186f1acdd 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.750'; -use constant AGENT_BUILD => '201029'; +use constant AGENT_BUILD => '201123'; # 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 698b2439d2..9f3ebf71f8 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.750 -%define release 201029 +%define release 201123 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 8d18a817fe..1e57d03518 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.750 -%define release 201029 +%define release 201123 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 81a292285e..77209d6a29 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.750" -PI_BUILD="201029" +PI_BUILD="201123" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index f6493723fd..0adc7de316 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{201029} +{201123} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index bac75d8cd5..22ea7a82ce 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.750(Build 201029)") +#define PANDORA_VERSION ("7.0NG.750(Build 201123)") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 070d4c6fbd..3c4a7cb83f 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.750(Build 201029))" + VALUE "ProductVersion", "(7.0NG.750(Build 201123))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 304b66c7a6..f560cd0126 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.750-201029 +Version: 7.0NG.750-201123 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 a7ca73a213..42b044ae66 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.750-201029" +pandora_version="7.0NG.750-201123" package_pear=0 package_pandora=1 diff --git a/pandora_console/extensions/agents_modules.php b/pandora_console/extensions/agents_modules.php index 5f9a984048..eb699b7467 100644 --- a/pandora_console/extensions/agents_modules.php +++ b/pandora_console/extensions/agents_modules.php @@ -657,7 +657,7 @@ function mainAgentsModules() if ($recursion) { $filter_groups['id_grupo'] = array_merge( $group_id, - groups_get_id_recursive($group_id, true) + groups_get_children_ids($group_id, true) ); } else { $filter_groups['id_grupo'] = $group_id; diff --git a/pandora_console/extensions/module_groups.php b/pandora_console/extensions/module_groups.php index 76225c0751..50a0de4d78 100644 --- a/pandora_console/extensions/module_groups.php +++ b/pandora_console/extensions/module_groups.php @@ -86,7 +86,6 @@ function mainModuleGroups() ); $info = $tree_group->getArray(); $info = groupview_plain_groups($info); - $counter = count($info); $offset = get_parameter('offset', 0); $agent_group_search = get_parameter('agent_group_search', ''); $module_group_search = get_parameter('module_group_search', ''); @@ -134,6 +133,8 @@ function mainModuleGroups() $ids_group = -1; } + $counter = count($info); + $condition_critical = modules_get_state_condition(AGENT_MODULE_STATUS_CRITICAL_ALERT); $condition_warning = modules_get_state_condition(AGENT_MODULE_STATUS_WARNING_ALERT); $condition_unknown = modules_get_state_condition(AGENT_MODULE_STATUS_UNKNOWN); diff --git a/pandora_console/extensions/resource_exportation.php b/pandora_console/extensions/resource_exportation.php index 3946ec053d..16cf674ab6 100755 --- a/pandora_console/extensions/resource_exportation.php +++ b/pandora_console/extensions/resource_exportation.php @@ -92,7 +92,11 @@ function output_xml_report($id) $group = db_get_value('nombre', 'tgrupo', 'id_grupo', $report['id_group']); echo '<group><![CDATA['.io_safe_output($group)."]]></group>\n"; - $items = db_get_all_rows_field_filter('treport_content', 'id_report', $report['id_report']); + $items = db_get_all_rows_field_filter( + 'treport_content', + 'id_report', + $report['id_report'] + ); foreach ($items as $item) { echo "<item>\n"; echo '<type>'.io_safe_output($item['type'])."</type>\n"; diff --git a/pandora_console/extensions/resource_registration.php b/pandora_console/extensions/resource_registration.php index dae61e3a78..80fed2cf6c 100755 --- a/pandora_console/extensions/resource_registration.php +++ b/pandora_console/extensions/resource_registration.php @@ -37,8 +37,16 @@ function insert_item_report($report_id, $values) ui_print_result_message( $result, - sprintf(__("Success add '%s' item in report '%s'."), $values['type'], $name), - sprintf(__("Error create '%s' item in report '%s'."), $values['type'], $name) + sprintf( + __("Success add '%s' item in report '%s'."), + $values['type'], + $name + ), + sprintf( + __("Error create '%s' item in report '%s'."), + $values['type'], + $name + ) ); } } @@ -55,9 +63,12 @@ function process_upload_xml_report($xml, $group_filter=0) $posible_name = $values['name']; $exist = true; $loops = 30; - // Loops to exit or tries + // Loops to exit or tries. while ($exist && $loops > 0) { - $exist = (bool) db_get_row_filter('treport', ['name' => io_safe_input($posible_name)]); + $exist = (bool) db_get_row_filter( + 'treport', + ['name' => io_safe_input($posible_name)] + ); if ($exist) { $loops--; @@ -74,7 +85,7 @@ function process_upload_xml_report($xml, $group_filter=0) ); break; } else if ($loops != 30) { - ui_print_error_message( + ui_print_warning_message( sprintf( __("Warning create '%s' report, the name exist, the report have a name %s."), $reportElement->name, @@ -89,13 +100,22 @@ function process_upload_xml_report($xml, $group_filter=0) break; } - $id_group = db_get_value('id_grupo', 'tgrupo', 'nombre', $reportElement->group); - if ($id_group === false) { - ui_print_error_message(__("Error the report haven't group.")); - break; + if (isset($reportElement->group) === true + && empty($reportElement->group) === false + ) { + $id_group = db_get_value( + 'id_grupo', + 'tgrupo', + 'nombre', + $reportElement->group + ); + if ($id_group === false) { + ui_print_error_message(__("Error the report haven't group.")); + break; + } } - if (isset($reportElement->description)) { + if (isset($reportElement->description) === true) { $values['description'] = $reportElement->description; } @@ -108,9 +128,19 @@ function process_upload_xml_report($xml, $group_filter=0) ); if ($id_report) { - db_pandora_audit('Report management', 'Create report '.$id_report, false, false); + db_pandora_audit( + 'Report management', + 'Create report '.$id_report, + false, + false + ); } else { - db_pandora_audit('Report management', 'Fail to create report', false, false); + db_pandora_audit( + 'Report management', + 'Fail to create report', + false, + false + ); break; } @@ -119,45 +149,52 @@ function process_upload_xml_report($xml, $group_filter=0) $values = []; $values['id_report'] = $id_report; - if (isset($item['description'])) { + if (isset($item['description']) === true) { $values['description'] = io_safe_input($item['description']); } - if (isset($item['period'])) { + if (isset($item['period']) === true) { $values['period'] = io_safe_input($item['period']); } - if (isset($item['type'])) { + if (isset($item['type']) === true) { $values['type'] = io_safe_input($item['type']); } $agents_item = []; - if (isset($item['agent'])) { + if (isset($item['agent']) === true) { $agents = agents_get_agents( ['id_grupo' => $group_filter], [ 'id_agente', - 'nombre', + 'alias', ] ); - $agent_clean = str_replace(['[', ']'], '', $item['agent']); + $agent_clean = str_replace( + [ + '[', + ']', + ], + '', + io_safe_output($item['agent']) + ); $regular_expresion = ($agent_clean != $item['agent']); foreach ($agents as $agent) { if ($regular_expresion) { - if ((bool) preg_match('/'.$agent_clean.'/', io_safe_output($agent['nombre']))) { - $agents_item[$agent['id_agente']]['name'] = $agent['nombre']; + if ((bool) preg_match('/'.$agent_clean.'/', io_safe_output($agent['alias']))) { + $agents_item[$agent['id_agente']]['name'] = $agent['alias']; } } else { - if ($agent_clean == io_safe_output($agent['nombre'])) { - $agents_item[$agent['id_agente']]['name'] = $agent['nombre']; + if ($agent_clean == io_safe_output($agent['alias'])) { + $agents_item[$agent['id_agente']]['name'] = $agent['alias']; } } } } - if (isset($item['module'])) { + if (isset($item['module']) === true) { $module_clean = str_replace(['[', ']'], '', $item['module']); $regular_expresion = ($module_clean != $item['module']); diff --git a/pandora_console/extras/mr/42.sql b/pandora_console/extras/mr/42.sql index 26f20e0f0a..f4bed54d16 100644 --- a/pandora_console/extras/mr/42.sql +++ b/pandora_console/extras/mr/42.sql @@ -31,4 +31,6 @@ ALTER TABLE `treport` ADD COLUMN `index_render` tinyint(1) NOT NULL DEFAULT 1; ALTER TABLE `treport_template` ADD COLUMN `cover_page_render` tinyint(1) NOT NULL DEFAULT 1; ALTER TABLE `treport_template` ADD COLUMN `index_render` tinyint(1) NOT NULL DEFAULT 1; +UPDATE `tconfig` SET value = '{"0.00000038580247":"Seconds to months","0.00000165343915":"Seconds to weeks","0.00001157407407":"Seconds to days","0.01666666666667":"Seconds to minutes","0.00000000093132":"Bytes to Gigabytes","0.00000095367432":"Bytes to Megabytes","0.00097656250000":"Bytes to Kilobytes","0.00000001653439":"Timeticks to weeks","0.00000011574074":"Timeticks to days"}' WHERE token = 'post_process_custom_values'; + 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 664a7749e1..b1e8f60aad 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 @@ -1405,6 +1405,7 @@ INSERT INTO `tconfig` (`token`, `value`) VALUES ('cr_incident_type', ''); INSERT INTO `tconfig` (`token`, `value`) VALUES ('cr_incident_status', ''); INSERT INTO `tconfig` (`token`, `value`) VALUES ('cr_incident_title', ''); INSERT INTO `tconfig` (`token`, `value`) VALUES ('cr_incident_content', ''); +INSERT INTO `tconfig` (`token`, `value`) VALUES ('post_process_custom_values', '{"0.00000038580247":"Seconds to months","0.00000165343915":"Seconds to weeks","0.00001157407407":"Seconds to days","0.01666666666667":"Seconds to minutes","0.00000000093132":"Bytes to Gigabytes","0.00000095367432":"Bytes to Megabytes","0.00097656250000":"Bytes to Kilobytes","0.00000001653439":"Timeticks to weeks","0.00000011574074":"Timeticks to days"}'); -- --------------------------------------------------------------------- -- Table `tconfig_os` diff --git a/pandora_console/general/login_page.php b/pandora_console/general/login_page.php index c4cd8482bc..59257907ad 100755 --- a/pandora_console/general/login_page.php +++ b/pandora_console/general/login_page.php @@ -114,6 +114,13 @@ foreach ($custom_fields as $field) { } } +// Connection lost alert. +ui_require_css_file('register', 'include/styles/', true); +ui_require_javascript_file('connection_check'); +$conn_title = __('Connection with server has been lost'); +$conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); +ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); + // Get the custom icons. $docs_logo = ui_get_docs_logo(); $support_logo = ui_get_support_logo(); @@ -450,7 +457,12 @@ if ($login_screen == 'logout') { echo '<div class="content_message_alert">'; echo '<div class="text_message_alert">'; echo '<h1>'.__('Logged out').'</h1>'; - echo '<p>'.__('Your session has ended. Please close your browser window to close this %s session.', get_product_name()).'</p>'; + if (empty($config['logout_msg']) === true) { + echo '<p>'.__('Your session has ended. Please close your browser window to close this %s session.', get_product_name()).'</p>'; + } else { + echo '<p>'.__($config['logout_msg']).'</p>'; + } + echo '</div>'; echo '<div class="button_message_alert">'; html_print_submit_button('Ok', 'hide-login-logout', false); diff --git a/pandora_console/general/register.php b/pandora_console/general/register.php index e7097b994e..8c10adc32b 100644 --- a/pandora_console/general/register.php +++ b/pandora_console/general/register.php @@ -148,7 +148,8 @@ if ($initial && users_is_admin()) { config_wiz_modal( false, true, - (($registration === true) ? 'show_registration_wizard()' : null) + (($registration === true) ? 'show_registration_wizard()' : null), + true ); } @@ -159,7 +160,8 @@ if (!$config['disabled_newsletter']) { false, // Launch only if not being launch from 'initial'. !$initial, - (($show_newsletter === true) ? 'force_run_newsletter()' : null) + (($show_newsletter === false) ? 'force_run_newsletter()' : null), + true ); } else { if ($show_newsletter) { @@ -167,7 +169,8 @@ if (!$config['disabled_newsletter']) { newsletter_wiz_modal( false, // Launch only if not being call from 'registration'. - !$registration && !$initial + !$registration && !$initial, + true ); } } diff --git a/pandora_console/godmode/agentes/agent_manager.php b/pandora_console/godmode/agentes/agent_manager.php index f4014de907..d1c7ae5224 100644 --- a/pandora_console/godmode/agentes/agent_manager.php +++ b/pandora_console/godmode/agentes/agent_manager.php @@ -149,7 +149,7 @@ if (is_ajax()) { ui_require_javascript_file('openlayers.pandora'); -$new_agent = (bool) get_parameter('new_agent'); +$new_agent = (empty($id_agente)) ? true : false; if (! isset($id_agente) && ! $new_agent) { db_pandora_audit('ACL Violation', 'Trying to access agent manager witout an agent'); @@ -1222,6 +1222,7 @@ ui_require_jquery_file('bgiframe'); $(document).ready (function() { + var $id_agent = '<?php echo $id_agente; ?>'; var previous_primary_group_select; $("#grupo").on('focus', function () { previous_primary_group_select = this.value; @@ -1276,12 +1277,14 @@ ui_require_jquery_file('bgiframe'); } }); - paint_qrcode( - "<?php echo ui_get_full_url('mobile/index.php?page=agent&id='.$id_agente); ?>", - "#qr_code_agent_view", - 128, - 128 - ); + if (typeof $id_agent !== 'undefined' && $id_agent !== '0') { + paint_qrcode( + "<?php echo ui_get_full_url('mobile/index.php?page=agent&id='.$id_agente); ?>", + "#qr_code_agent_view", + 128, + 128 + ); + } $("#text-agente").prop('readonly', true); }); diff --git a/pandora_console/godmode/agentes/modificar_agente.php b/pandora_console/godmode/agentes/modificar_agente.php index d4036bd68c..77d8f06b46 100644 --- a/pandora_console/godmode/agentes/modificar_agente.php +++ b/pandora_console/godmode/agentes/modificar_agente.php @@ -408,7 +408,7 @@ if ($ag_group > 0) { $ag_groups = []; $ag_groups = (array) $ag_group; if ($recursion) { - $ag_groups = groups_get_id_recursive($ag_group, true); + $ag_groups = groups_get_children_ids($ag_group, true); } $user_groups_to_sql = implode(',', $ag_groups); @@ -754,7 +754,6 @@ if (check_acl($config['id_user'], 0, 'AW')) { // Create agent button. echo '<div style="text-align: right;">'; echo '<form method="post" action="index.php?sec=gagente&sec2=godmode/agentes/configurar_agente">'; - html_print_input_hidden('new_agent', 1); html_print_submit_button( __('Create agent'), 'crt-2', diff --git a/pandora_console/godmode/agentes/module_manager_editor_common.php b/pandora_console/godmode/agentes/module_manager_editor_common.php index e6d384e5e4..df0bd80ef1 100644 --- a/pandora_console/godmode/agentes/module_manager_editor_common.php +++ b/pandora_console/godmode/agentes/module_manager_editor_common.php @@ -535,20 +535,30 @@ $table_advanced->data[0][1] = html_print_input_text( ); $table_advanced->data[0][3] = __('Unit'); -// $table_advanced->data[1][4] = html_print_input_text ('unit', $unit, '', 20, 65, true, -// $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy); -// $table_advanced->colspan[1][4] = 3; -$table_advanced->data[0][4] = html_print_extended_select_for_unit( +$table_advanced->data[0][4] = html_print_input_text ( 'unit', $unit, '', - '', - '0', - false, + 20, + 65, true, + $disabledBecauseInPolicy, false, - false + '', + $classdisabledBecauseInPolicy ); +// $table_advanced->colspan[1][4] = 3; +//$table_advanced->data[0][4] = html_print_extended_select_for_unit( +// 'unit', +// $unit, +// '', +// '', +// '0', +// false, +// true, +// false, +// false +//); $table_advanced->colspan[0][4] = 3; $module_id_policy_module = 0; @@ -1340,115 +1350,117 @@ $(document).ready (function () { var type_name_selected = type_names[type_selected]; var element = document.getElementById("module_type_help"); var language = "<?php echo $config['language']; ?>" ; - element.onclick = function (event) { - if(type_name_selected == 'async_data' || - type_name_selected == 'async_proc' || - type_name_selected == 'async_string' || - type_name_selected == 'generic_proc'|| - type_name_selected == 'generic_data' || - type_name_selected == 'generic_data_inc' || - type_name_selected == 'generic_data_inc_abs'|| - type_name_selected == 'generic_data_string' || - type_name_selected == 'keep_alive' - ){ - if (language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Operacion&printable=yes#Tipos_de_m.C3.B3dulos', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Operations&printable=yes#Types_of_Modules', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'remote_icmp' || - type_name_selected == 'remote_icmp_proc' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#ICMP_Monitoring', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'remote_snmp_string' || - type_name_selected == 'remote_snmp_proc' || - type_name_selected == 'remote_snmp_inc' || - type_name_selected == 'remote_snmp' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizando_con_m.C3.B3dulos_de_red_tipo_SNMP', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#Monitoring_by_Network_Modules_with_SNMP', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'remote_tcp_string' || - type_name_selected == 'remote_tcp_proc' || - type_name_selected == 'remote_tcp_inc' || - type_name_selected == 'remote_tcp' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_TCP', - '_blank', - 'width=800,height=600' - ); + if (typeof element !== 'undefined' && element !== null) { + element.onclick = function (event) { + if(type_name_selected == 'async_data' || + type_name_selected == 'async_proc' || + type_name_selected == 'async_string' || + type_name_selected == 'generic_proc'|| + type_name_selected == 'generic_data' || + type_name_selected == 'generic_data_inc' || + type_name_selected == 'generic_data_inc_abs'|| + type_name_selected == 'generic_data_string' || + type_name_selected == 'keep_alive' + ){ + if (language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Operacion&printable=yes#Tipos_de_m.C3.B3dulos', + '_blank', + 'width=800,height=600' + ); } else{ window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#TCP_Monitoring', - '_blank', - 'width=800,height=600' - ); - } - } - if(type_name_selected == 'web_data' || - type_name_selected == 'web_proc' || - type_name_selected == 'web_content_data' || - type_name_selected == 'web_content_string' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_web&printable=yes#Creaci.C3.B3n_de_m.C3.B3dulos_web', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Web_Monitoring&printable=yes#Creating_Web_Modules', - '_blank', - 'width=800,height=600' - ); + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Operations&printable=yes#Types_of_Modules', + '_blank', + 'width=800,height=600' + ); } + + + } + if(type_name_selected == 'remote_icmp' || + type_name_selected == 'remote_icmp_proc' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#ICMP_Monitoring', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'remote_snmp_string' || + type_name_selected == 'remote_snmp_proc' || + type_name_selected == 'remote_snmp_inc' || + type_name_selected == 'remote_snmp' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizando_con_m.C3.B3dulos_de_red_tipo_SNMP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#Monitoring_by_Network_Modules_with_SNMP', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'remote_tcp_string' || + type_name_selected == 'remote_tcp_proc' || + type_name_selected == 'remote_tcp_inc' || + type_name_selected == 'remote_tcp' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_TCP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#TCP_Monitoring', + '_blank', + 'width=800,height=600' + ); + } + } + if(type_name_selected == 'web_data' || + type_name_selected == 'web_proc' || + type_name_selected == 'web_content_data' || + type_name_selected == 'web_content_string' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_web&printable=yes#Creaci.C3.B3n_de_m.C3.B3dulos_web', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Web_Monitoring&printable=yes#Creating_Web_Modules', + '_blank', + 'width=800,height=600' + ); + } + } } } diff --git a/pandora_console/godmode/agentes/planned_downtime.editor.php b/pandora_console/godmode/agentes/planned_downtime.editor.php index b3e7029dbd..4aceac701e 100644 --- a/pandora_console/godmode/agentes/planned_downtime.editor.php +++ b/pandora_console/godmode/agentes/planned_downtime.editor.php @@ -877,7 +877,7 @@ if ($id_downtime > 0) { $filter_cond = ''; if ($filter_group > 0) { if ($recursion) { - $rg = groups_get_id_recursive($filter_group, true); + $rg = groups_get_children_ids($filter_group, true); $filter_cond .= ' AND id_grupo IN ('; $i = 0; diff --git a/pandora_console/godmode/events/event_edit_filter.php b/pandora_console/godmode/events/event_edit_filter.php index 56201e3a28..a93f38bfa1 100644 --- a/pandora_console/godmode/events/event_edit_filter.php +++ b/pandora_console/godmode/events/event_edit_filter.php @@ -130,6 +130,16 @@ if ($update || $create) { $id_agent = (int) get_parameter('id_agent'); $text_module = get_parameter('text_module', ''); $id_agent_module = (int) get_parameter('module_search_hidden'); + if ($text_module === '') { + $text_module = io_safe_output( + db_get_value_filter( + 'nombre', + 'tagente_modulo', + ['id_agente_modulo' => $id_agent_module] + ) + ); + } + $pagination = get_parameter('pagination', ''); $event_view_hr = get_parameter('event_view_hr', ''); $id_user_ack = get_parameter('id_user_ack', ''); diff --git a/pandora_console/godmode/massive/massive_add_action_alerts.php b/pandora_console/godmode/massive/massive_add_action_alerts.php index 9abac11def..52fd5bed07 100755 --- a/pandora_console/godmode/massive/massive_add_action_alerts.php +++ b/pandora_console/godmode/massive/massive_add_action_alerts.php @@ -67,10 +67,30 @@ if ($add) { $modules = get_parameter('module'); $modules_id = []; if (!empty($modules)) { + $modules_id = []; + foreach ($modules as $module) { foreach ($id_agents as $id_agent) { - $module_id = modules_get_agentmodule_id($module, $id_agent); - $modules_id[] = $module_id['id_agente_modulo']; + if ($module == '0') { + // Get all modules of agent. + $agent_modules = db_get_all_rows_filter( + 'tagente_modulo', + ['id_agente' => $id_agent], + 'id_agente_modulo' + ); + + $agent_modules_id = array_map( + function ($field) { + return $field['id_agente_modulo']; + }, + $agent_modules + ); + + $modules_id = array_merge($modules_id, $agent_modules_id); + } else { + $module_id = modules_get_agentmodule_id($module, $id_agent); + $modules_id[] = $module_id['id_agente_modulo']; + } } } diff --git a/pandora_console/godmode/massive/massive_add_alerts.php b/pandora_console/godmode/massive/massive_add_alerts.php index bf52fd0459..7ed99d8277 100755 --- a/pandora_console/godmode/massive/massive_add_alerts.php +++ b/pandora_console/godmode/massive/massive_add_alerts.php @@ -106,15 +106,31 @@ function process_manage_add($id_alert_template, $id_agents, $module_names) return false; } + $modules_id = []; + foreach ($module_names as $module) { foreach ($id_agents as $id_agent) { - $module_id = modules_get_agentmodule_id($module, $id_agent); - $modules_id[] = $module_id['id_agente_modulo']; - } - } + if ($module == '0') { + // Get all modules of agent. + $agent_modules = db_get_all_rows_filter( + 'tagente_modulo', + ['id_agente' => $id_agent], + 'id_agente_modulo' + ); - if (count($module_names) == 1 && $module_names[0] == '0') { - $modules_id = agents_common_modules($id_agents, false, true); + $agent_modules_id = array_map( + function ($field) { + return $field['id_agente_modulo']; + }, + $agent_modules + ); + + $modules_id = array_merge($modules_id, $agent_modules_id); + } else { + $module_id = modules_get_agentmodule_id($module, $id_agent); + $modules_id[] = $module_id['id_agente_modulo']; + } + } } $conttotal = 0; diff --git a/pandora_console/godmode/massive/massive_delete_action_alerts.php b/pandora_console/godmode/massive/massive_delete_action_alerts.php index 832765d4de..5f658fade6 100644 --- a/pandora_console/godmode/massive/massive_delete_action_alerts.php +++ b/pandora_console/godmode/massive/massive_delete_action_alerts.php @@ -66,10 +66,29 @@ if ($delete) { $modules = (array) get_parameter('module'); $modules_id = []; if (!empty($modules)) { + $modules_id = []; foreach ($modules as $module) { foreach ($id_agents as $id_agent) { - $module_id = modules_get_agentmodule_id($module, $id_agent); - $modules_id[] = $module_id['id_agente_modulo']; + if ($module == '0') { + // Get all modules of agent. + $agent_modules = db_get_all_rows_filter( + 'tagente_modulo', + ['id_agente' => $id_agent], + 'id_agente_modulo' + ); + + $agent_modules_id = array_map( + function ($field) { + return $field['id_agente_modulo']; + }, + $agent_modules + ); + + $modules_id = array_merge($modules_id, $agent_modules_id); + } else { + $module_id = modules_get_agentmodule_id($module, $id_agent); + $modules_id[] = $module_id['id_agente_modulo']; + } } } diff --git a/pandora_console/godmode/massive/massive_delete_alerts.php b/pandora_console/godmode/massive/massive_delete_alerts.php index c9bcda46ba..c5407ed365 100755 --- a/pandora_console/godmode/massive/massive_delete_alerts.php +++ b/pandora_console/godmode/massive/massive_delete_alerts.php @@ -40,7 +40,7 @@ if (is_ajax()) { $keys_prefix = (string) get_parameter('keys_prefix', ''); if ($recursion) { - $groups = groups_get_id_recursive($id_group, true); + $groups = groups_get_children_ids($id_group, true); } else { $groups = [$id_group]; } diff --git a/pandora_console/godmode/massive/massive_delete_modules.php b/pandora_console/godmode/massive/massive_delete_modules.php index 7d8d64141a..6b31331d1b 100755 --- a/pandora_console/godmode/massive/massive_delete_modules.php +++ b/pandora_console/godmode/massive/massive_delete_modules.php @@ -450,7 +450,7 @@ $table->data['form_modules_2'][1] = html_print_select( '', false, 'width:100%' -); +).' '.__('Select all modules').' '.html_print_checkbox('select_all_modules', 1, false, true, false, '', false, "class='static'"); $table->data['form_modules_2'][2] = __('When select modules'); $table->data['form_modules_2'][2] .= '<br>'; @@ -522,7 +522,8 @@ $table->data['form_agents_3'][1] = html_print_select( '', false, 'width:100%' -); +).' '.__('Select all agents').' '.html_print_checkbox('select_all_agents', 1, false, true, false, '', false, "class='static'"); + $table->data['form_agents_3'][2] = __('When select agents'); $table->data['form_agents_3'][2] .= '<br>'; $table->data['form_agents_3'][2] .= html_print_select( @@ -588,6 +589,44 @@ if ($selection_mode == 'modules') { var limit_parameters_massive = <?php echo $config['limit_parameters_massive']; ?>; $(document).ready (function () { + $("#checkbox-select_all_modules").change(function() { + if( $('#checkbox-select_all_modules').prop('checked')) { + $("#module_name option").prop('selected', 'selected'); + $("#module_name").trigger('change'); + } else { + $("#module_name option").prop('selected', false); + $("#module_name").trigger('change'); + } + }); + + $("#module_name").change(function() { + var options_length = $("#module_name option").length; + var options_selected_length = $("#module_name option:selected").length; + + if (options_selected_length < options_length) { + $('#checkbox-select_all_modules').prop("checked", false); + } + }); + + $("#checkbox-select_all_agents").change(function() { + if( $('#checkbox-select_all_agents').prop('checked')) { + $("#id_agents option").prop('selected', 'selected'); + $("#id_agents").trigger('change'); + } else { + $("#id_agents option").prop('selected', false); + $("#id_agents").trigger('change'); + } + }); + + $("#id_agents").change(function() { + var options_length = $("#id_agents option").length; + var options_selected_length = $("#id_agents option:selected").length; + + if (options_selected_length < options_length) { + $('#checkbox-select_all_agents').prop("checked", false); + } + }); + $("#id_agents").change(agent_changed_by_multiple_agents); $("#module_name").change(module_changed_by_multiple_modules); @@ -680,7 +719,7 @@ $(document).ready (function () { $('#groups_select').val(-1); } - $('input[type=checkbox]').change ( + $('input[type=checkbox]').not(".static").change ( function () { if (this.id == "checkbox-force_type") { if (this.checked) { diff --git a/pandora_console/godmode/massive/massive_edit_modules.php b/pandora_console/godmode/massive/massive_edit_modules.php index 8c5a611847..1948ba4fa0 100755 --- a/pandora_console/godmode/massive/massive_edit_modules.php +++ b/pandora_console/godmode/massive/massive_edit_modules.php @@ -406,7 +406,8 @@ $table->data['form_modules_2'][1] = html_print_select( true, true, true -); +).' '.__('Select all modules').' '.html_print_checkbox('select_all_modules', 1, false, true, false, '', false, "class='static'"); + $table->data['form_modules_2'][2] = __('When select modules'); $table->data['form_modules_2'][2] .= '<br>'; $table->data['form_modules_2'][2] .= html_print_select( @@ -491,7 +492,7 @@ $table->data['form_agents_3'][1] = html_print_select( true, true, false -); +).' '.__('Select all agents').' '.html_print_checkbox('select_all_agents', 1, false, true, false, '', false, "class='static'"); $table->data['form_agents_3'][2] = __('When select agents'); $table->data['form_agents_3'][2] .= '<br>'; @@ -1212,7 +1213,45 @@ $(document).ready (function () { return false; } }); - + + $("#checkbox-select_all_modules").change(function() { + if( $('#checkbox-select_all_modules').prop('checked')) { + $("#module_name option").prop('selected', 'selected'); + $("#module_name").trigger('change'); + } else { + $("#module_name option").prop('selected', false); + $("#module_name").trigger('change'); + } + }); + + $("#module_name").change(function() { + var options_length = $("#module_name option").length; + var options_selected_length = $("#module_name option:selected").length; + + if (options_selected_length < options_length) { + $('#checkbox-select_all_modules').prop("checked", false); + } + }); + + $("#checkbox-select_all_agents").change(function() { + if( $('#checkbox-select_all_agents').prop('checked')) { + $("#id_agents option").prop('selected', 'selected'); + $("#id_agents").trigger('change'); + } else { + $("#id_agents option").prop('selected', false); + $("#id_agents").trigger('change'); + } + }); + + $("#id_agents").change(function() { + var options_length = $("#id_agents option").length; + var options_selected_length = $("#id_agents option:selected").length; + + if (options_selected_length < options_length) { + $('#checkbox-select_all_agents').prop("checked", false); + } + }); + $("#text-custom_ip_target").hide(); $("#id_agents").change(agent_changed_by_multiple_agents); @@ -1463,7 +1502,7 @@ $(document).ready (function () { $('#groups_select').val(-1); } - $('input[type=checkbox]').change ( + $('input[type=checkbox]').not(".static").change ( function () { if (this.id == "checkbox-force_type") { if (this.checked) { diff --git a/pandora_console/godmode/modules/manage_network_components_form_common.php b/pandora_console/godmode/modules/manage_network_components_form_common.php index 35c5648db2..d42e93c949 100644 --- a/pandora_console/godmode/modules/manage_network_components_form_common.php +++ b/pandora_console/godmode/modules/manage_network_components_form_common.php @@ -386,121 +386,124 @@ $next_row++; console.log(type_name_selected); var element = document.getElementById("module_type_help"); var language = "<?php echo $config['language']; ?>" ; - element.onclick = function (event) { - if(type_name_selected == 'async_data' || - type_name_selected == 'async_proc' || - type_name_selected == 'async_string' || - type_name_selected == 'generic_proc'|| - type_name_selected == 'generic_data' || - type_name_selected == 'generic_data_inc' || - type_name_selected == 'generic_data_inc_abs'|| - type_name_selected == 'generic_data_string' || - type_name_selected == 'keep_alive' - ){ - if (language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Operacion&printable=yes#Tipos_de_m.C3.B3dulos', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Operations&printable=yes#Types_of_Modules', - '_blank', - 'width=800,height=600' - ); - } - - + + if (typeof element !== 'undefined' && element !== null) { + element.onclick = function (event) { + if(type_name_selected == 'async_data' || + type_name_selected == 'async_proc' || + type_name_selected == 'async_string' || + type_name_selected == 'generic_proc'|| + type_name_selected == 'generic_data' || + type_name_selected == 'generic_data_inc' || + type_name_selected == 'generic_data_inc_abs'|| + type_name_selected == 'generic_data_string' || + type_name_selected == 'keep_alive' + ){ + if (language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Operacion&printable=yes#Tipos_de_m.C3.B3dulos', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Operations&printable=yes#Types_of_Modules', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'remote_icmp' || + type_name_selected == 'remote_icmp_proc' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#ICMP_Monitoring', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'remote_snmp_string' || + type_name_selected == 'remote_snmp_proc' || + type_name_selected == 'remote_snmp_inc' || + type_name_selected == 'remote_snmp' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizando_con_m.C3.B3dulos_de_red_tipo_SNMP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#Monitoring_by_Network_Modules_with_SNMP', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'remote_tcp_string' || + type_name_selected == 'remote_tcp_proc' || + type_name_selected == 'remote_tcp_inc' || + type_name_selected == 'remote_tcp' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_TCP', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#TCP_Monitoring', + '_blank', + 'width=800,height=600' + ); + } + + + } + if(type_name_selected == 'web_data' || + type_name_selected == 'web_proc' || + type_name_selected == 'web_content_data' || + type_name_selected == 'web_content_string' + ){ + if(language == 'es'){ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_web&printable=yes#Creaci.C3.B3n_de_m.C3.B3dulos_web', + '_blank', + 'width=800,height=600' + ); + } + else{ + window.open( + 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Web_Monitoring&printable=yes#Creating_Web_Modules', + '_blank', + 'width=800,height=600' + ); + } + + + } + } } - if(type_name_selected == 'remote_icmp' || - type_name_selected == 'remote_icmp_proc' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_ICMP', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#ICMP_Monitoring', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'remote_snmp_string' || - type_name_selected == 'remote_snmp_proc' || - type_name_selected == 'remote_snmp_inc' || - type_name_selected == 'remote_snmp' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizando_con_m.C3.B3dulos_de_red_tipo_SNMP', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#Monitoring_by_Network_Modules_with_SNMP', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'remote_tcp_string' || - type_name_selected == 'remote_tcp_proc' || - type_name_selected == 'remote_tcp_inc' || - type_name_selected == 'remote_tcp' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_remota&printable=yes#Monitorizaci.C3.B3n_TCP', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Remote_Monitoring&printable=yes#TCP_Monitoring', - '_blank', - 'width=800,height=600' - ); - } - - - } - if(type_name_selected == 'web_data' || - type_name_selected == 'web_proc' || - type_name_selected == 'web_content_data' || - type_name_selected == 'web_content_string' - ){ - if(language == 'es'){ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_es:Monitorizacion_web&printable=yes#Creaci.C3.B3n_de_m.C3.B3dulos_web', - '_blank', - 'width=800,height=600' - ); - } - else{ - window.open( - 'https://wiki.pandorafms.com/index.php?title=Pandora:Documentation_en:Web_Monitoring&printable=yes#Creating_Web_Modules', - '_blank', - 'width=800,height=600' - ); - } - - - } - } if (type_name_selected.match(/_string$/) == null) { // Numeric types diff --git a/pandora_console/godmode/reporting/map_builder.php b/pandora_console/godmode/reporting/map_builder.php index 9f8b8f0162..482b995f8f 100644 --- a/pandora_console/godmode/reporting/map_builder.php +++ b/pandora_console/godmode/reporting/map_builder.php @@ -278,7 +278,7 @@ if ($ag_group > 0) { $ag_groups = []; $ag_groups = (array) $ag_group; if ($recursion) { - $ag_groups = groups_get_id_recursive($ag_group, true); + $ag_groups = groups_get_children_ids($ag_group, true); } } diff --git a/pandora_console/godmode/reporting/reporting_builder.item_editor.php b/pandora_console/godmode/reporting/reporting_builder.item_editor.php index 4bb76a00fa..7762f7b752 100755 --- a/pandora_console/godmode/reporting/reporting_builder.item_editor.php +++ b/pandora_console/godmode/reporting/reporting_builder.item_editor.php @@ -3744,6 +3744,16 @@ $(document).ready (function () { $("#combo_group").change ( function () { + + // Alert report group must show all matches when selecting All group + // ignoring 'recursion' option. #6497. + if ($("#combo_group").val() == 0) { + $('#checkbox-recursion').attr('disabled',true) + $('#checkbox-recursion').attr('checked','checked') + } else { + $('#checkbox-recursion').removeAttr('disabled') + } + $("#id_agents").html(''); $("#id_agents2").html(''); $("#module").html(''); @@ -3772,6 +3782,7 @@ $(document).ready (function () { ); } ); + $("#combo_group").change(); $("#checkbox-recursion").change ( function () { diff --git a/pandora_console/godmode/reporting/reporting_builder.php b/pandora_console/godmode/reporting/reporting_builder.php index 6857a2cd39..724be2b1d5 100755 --- a/pandora_console/godmode/reporting/reporting_builder.php +++ b/pandora_console/godmode/reporting/reporting_builder.php @@ -1813,11 +1813,9 @@ switch ($action) { ); $values['id_group'] = get_parameter('combo_group'); - if ($values['server_name'] == '') { - $values['server_name'] = get_parameter( - 'combo_server' - ); - } + $values['server_name'] = get_parameter( + 'combo_server' + ); if ((($values['type'] == 'custom_graph') || ($values['type'] == 'automatic_custom_graph')) diff --git a/pandora_console/godmode/reporting/visual_console_favorite.php b/pandora_console/godmode/reporting/visual_console_favorite.php index b9f4fe28d7..66b4a21e30 100644 --- a/pandora_console/godmode/reporting/visual_console_favorite.php +++ b/pandora_console/godmode/reporting/visual_console_favorite.php @@ -115,7 +115,7 @@ if (!$own_info['is_admin'] && !check_acl($config['id_user'], 0, 'AW')) { $return_all_group, 'ag_group', $ag_group, - 'this.form.submit();', + '', '', 0, false, @@ -126,7 +126,7 @@ if (!$own_info['is_admin'] && !check_acl($config['id_user'], 0, 'AW')) { ); echo "</li></ul></li><li class='second_elements'><ul><li>"; echo __('Group Recursion'); - html_print_checkbox('recursion', 1, $recursion, false, false, 'this.form.submit()'); + html_print_checkbox('recursion', 1, $recursion, false, false, ''); echo '</li><li>'; echo "<input name='search_visual_console' type='submit' class='sub search' value='".__('Search')."'>"; echo '</li></ul></li></ul>'; @@ -143,7 +143,7 @@ if (!$own_info['is_admin'] && !check_acl($config['id_user'], 0, 'AW')) { $ag_groups = []; $ag_groups = (array) $ag_group; if ($recursion) { - $ag_groups = groups_get_id_recursive($ag_group, true); + $ag_groups = groups_get_children_ids($ag_group, true); } } else if ($own_info['is_admin']) { $returnAllGroups = 1; diff --git a/pandora_console/godmode/servers/modificar_server.php b/pandora_console/godmode/servers/modificar_server.php index 9062eab0a4..d7332b86b4 100644 --- a/pandora_console/godmode/servers/modificar_server.php +++ b/pandora_console/godmode/servers/modificar_server.php @@ -140,7 +140,7 @@ if (isset($_GET['server'])) { ui_print_error_message(__('There was a problem deleting the server')); } } else if (isset($_GET['update'])) { - $address = trim(get_parameter_post('address'), ' '); + $address = trim(io_safe_output(get_parameter_post('address')), ' '); $description = trim(get_parameter_post('description'), ' '); $id_server = get_parameter_post('server'); $exec_proxy = get_parameter_post('exec_proxy'); diff --git a/pandora_console/godmode/servers/servers.build_table.php b/pandora_console/godmode/servers/servers.build_table.php index 668ef26f0c..fd6f8d7a02 100644 --- a/pandora_console/godmode/servers/servers.build_table.php +++ b/pandora_console/godmode/servers/servers.build_table.php @@ -91,8 +91,20 @@ foreach ($servers as $server) { // Status $data[1] = ui_print_status_image(STATUS_SERVER_OK, '', true); - if (($server['status'] == 0) || (($date - time_w_fixed_tz($server['keepalive'])) > ($server['server_keepalive']) * 2)) { - $data[1] = ui_print_status_image(STATUS_SERVER_DOWN, '', true); + if ($server['status'] == -1) { + $data[1] = ui_print_status_image( + STATUS_SERVER_CRASH, + __('Server has crashed.'), + true + ); + } else if (($server['status'] == 0) + || (($date - time_w_fixed_tz($server['keepalive'])) > ($server['server_keepalive']) * 2) + ) { + $data[1] = ui_print_status_image( + STATUS_SERVER_DOWN, + __('Server is stopped.'), + true + ); } // Type diff --git a/pandora_console/godmode/update_manager/update_manager.offline.php b/pandora_console/godmode/update_manager/update_manager.offline.php index 8fb4447772..2461ec6980 100644 --- a/pandora_console/godmode/update_manager/update_manager.offline.php +++ b/pandora_console/godmode/update_manager/update_manager.offline.php @@ -44,6 +44,16 @@ if (! check_acl($config['id_user'], 0, 'PM') return; } +require_once $config['homedir'].'/include/functions_update_manager.php'; + + +if (update_manager_verify_license_expired()) { + ui_print_error_message( + __('The license has expired. Please contact Artica at info@artica.es') + ); + return; +} + $baseurl = ui_get_full_url(false, false, false, false); $current_package = db_get_value( diff --git a/pandora_console/godmode/update_manager/update_manager.online.php b/pandora_console/godmode/update_manager/update_manager.online.php index a1524d5518..6ac5c61f9b 100644 --- a/pandora_console/godmode/update_manager/update_manager.online.php +++ b/pandora_console/godmode/update_manager/update_manager.online.php @@ -94,6 +94,13 @@ if ($upload_max_filesize < $PHPupload_max_filesize_min) { $php_settings_fine++; } +if (update_manager_verify_license_expired()) { + ui_print_error_message( + __('The license has expired. Please contact Artica at info@artica.es') + ); + return; +} + // Verify registry. if (update_manager_verify_registration() === false) { ui_require_css_file('register'); diff --git a/pandora_console/godmode/users/configure_user.php b/pandora_console/godmode/users/configure_user.php index b98d35e003..acf412b345 100644 --- a/pandora_console/godmode/users/configure_user.php +++ b/pandora_console/godmode/users/configure_user.php @@ -1313,6 +1313,7 @@ $(document).ready (function () { var img_delete = '<?php echo $delete_image; ?>'; var id_user = '<?php echo io_safe_output($id); ?>'; + var is_metaconsole = '<?php echo $meta; ?>'; var data = []; $('input:image[name="add"]').click(function (e) { @@ -1357,7 +1358,7 @@ $(document).ready (function () { $('input:image[name="del"]').click(function (e) { e.preventDefault(); var rows = $("#table_profiles tr").length; - if (rows <= 3) { + if ((is_metaconsole === '1' && rows <= 4) || (is_metaconsole === '' && rows <= 3)) { if (!confirm('<?php echo __('Deleting last profile will delete this user'); ?>' + '. ' + '<?php echo __('Are you sure?'); ?>')) { return; } @@ -1379,21 +1380,39 @@ $(document).ready (function () { success: function (data) { row.remove(); var rows = $("#table_profiles tr").length; - if (rows <= 2) { + if ((is_metaconsole === '1' && rows <= 3) || (is_metaconsole === '' && rows <= 2)) { window.location.replace("<?php echo ui_get_full_url('index.php?sec=gusuarios&sec2=godmode/users/user_list&tab=user&pure=0', false, false, false); ?>"); } } }); }); - $('#submit-crtbutton').click(function (e) { + function checkProfiles(e) { e.preventDefault(); - var rows = $("#table_profiles tr").length; - if (rows <= 2) { - alert('<?php echo __('please add a profile'); ?>'); + if ($('input[name="is_admin"]:checked').val() == 1) { + // Admin does not require profiles. + $('#user_profile_form').submit(); } else { - this.form.submit(); + if ($('#table_profiles tbody').children().length == 1) { + confirmDialog({ + title: "<?php echo __('Warning'); ?>", + message: "<?php echo __('User will be created without profiles assigned and won\'t be able to log in, are you sure?'); ?>", + onAccept: function() { + $('#user_profile_form').submit(); + } + }); + } else { + $('#user_profile_form').submit(); + } } + } + + $('#submit-crtbutton').click(function (e) { + checkProfiles(e); + }); + + $('#submit-uptbutton').click(function (e) { + checkProfiles(e); }); }); diff --git a/pandora_console/images/status_sets/default/server_crash.png b/pandora_console/images/status_sets/default/server_crash.png new file mode 100644 index 0000000000..5bee46f76c Binary files /dev/null and b/pandora_console/images/status_sets/default/server_crash.png differ diff --git a/pandora_console/images/status_sets/default/server_crash_ball.png b/pandora_console/images/status_sets/default/server_crash_ball.png new file mode 100644 index 0000000000..fea84fee55 Binary files /dev/null and b/pandora_console/images/status_sets/default/server_crash_ball.png differ diff --git a/pandora_console/include/ajax/events.php b/pandora_console/include/ajax/events.php index 230b55a476..4e796c2539 100644 --- a/pandora_console/include/ajax/events.php +++ b/pandora_console/include/ajax/events.php @@ -114,7 +114,9 @@ if ($get_comments) { sprintf( ' HAVING max_id_evento = %d', $event['id_evento'] - ) + ), + // True for show comments of validated events. + true ); if ($events !== false) { $event = $events[0]; @@ -331,17 +333,52 @@ if ($get_filter_values) { if ($event_filter === false) { $event_filter = [ - 'status' => EVENT_NO_VALIDATED, - 'event_view_hr' => $config['event_view_hr'], - 'group_rep' => 1, - 'tag_with' => [], - 'tag_without' => [], - 'history' => false, + 'status' => EVENT_NO_VALIDATED, + 'event_view_hr' => $config['event_view_hr'], + 'group_rep' => 1, + 'tag_with' => [], + 'tag_without' => [], + 'history' => false, + 'module_search' => '', + 'filter_only_alert' => '-1', + 'user_comment' => '', + 'id_extra' => '', + 'id_user_ack' => '', + 'date_from' => '', + 'date_to' => '', + 'severity' => '', + 'event_type' => '', + 'group_rep' => 0, + 'id_group' => 0, + 'id_group_filter' => 0, + 'group_name' => 'All', + 'text_agent' => '', + 'id_agent' => 0, + 'id_name' => 'None', + 'filter_id' => 0, ]; + } else { + $event_filter['module_search'] = io_safe_output(db_get_value_filter('nombre', 'tagente_modulo', ['id_agente_modulo' => $event_filter['id_agent_module']])); + $a = array_keys(users_get_groups(false)); + $event_filter['group_name'] = ''; + foreach ($a as $key => $value) { + if ($value == $event_filter['id_group']) { + $event_filter['group_name'] = db_get_value('nombre', 'tgrupo', 'id_grupo', $event_filter['id_group_filter']); + if ($event_filter['group_name'] === false) { + $event_filter['group_name'] = __('All'); + } + } + } + + $event_filter['module_search'] = io_safe_output(db_get_value_filter('nombre', 'tagente_modulo', ['id_agente_modulo' => $event_filter['id_agent_module']])); } $event_filter['search'] = io_safe_output($event_filter['search']); $event_filter['id_name'] = io_safe_output($event_filter['id_name']); + $event_filter['text_agent'] = io_safe_output($event_filter['text_agent']); + $event_filter['source'] = io_safe_output($event_filter['source']); + + $event_filter['tag_with'] = base64_encode( io_safe_output($event_filter['tag_with']) ); @@ -353,7 +390,7 @@ if ($get_filter_values) { } if ($load_filter_modal) { - $current = get_parameter('current_filter', ''); + $current = db_get_value_filter('default_event_filter', 'tusuario', ['id_user' => $config['id_user']]); $filters = events_get_event_filter_select(); $user_groups_array = users_get_groups_for_select( $config['id_user'], @@ -433,10 +470,12 @@ function load_form_filter() { }, function (data) { jQuery.each (data, function (i, val) { + console.log(val); if (i == 'id_name') $("#hidden-id_name").val(val); - if (i == 'id_group') - $("#id_group").val(val); + if (i == 'id_group'){ + $('#id_group').val(val); + } if (i == 'event_type') $("#event_type").val(val); if (i == 'severity') { @@ -446,9 +485,9 @@ function load_form_filter() { if (i == 'status') $("#status").val(val); if (i == 'search') - $("#text-search").val(val); + $('#text-search').val(val); if (i == 'text_agent') - $("#text_id_agent").val(val); + $('input[name=text_agent]').val(val); if (i == 'id_agent') $('input:hidden[name=id_agent]').val(val); if (i == 'id_agent_module') @@ -477,6 +516,15 @@ function load_form_filter() { $("#text-user_comment").val(val); if (i == 'id_source_event') $("#text-id_source_event").val(val); + if(i == 'date_from') + $("#text-date_from").val(val); + if(i == 'date_to') + $("#text-date_to").val(val); + if(i == 'module_search') + $('input[name=module_search]').val(val); + if(i == 'group_name') + $("#select2-id_group_filter-container").text(val); + }); reorder_tags_inputs(); // Update the info with the loaded filter @@ -1145,12 +1193,37 @@ if ($change_status) { $event_ids = get_parameter('event_ids'); $new_status = get_parameter('new_status'); - $return = events_change_status(explode(',', $event_ids), $new_status, $meta, $history); + $return = events_change_status( + explode(',', $event_ids), + $new_status, + $meta, + $history + ); - if ($return) { - echo 'status_ok'; + if ($return !== false) { + echo json_encode( + [ + 'status' => 'status_ok', + 'user' => db_get_value( + 'fullname', + 'tusuario', + 'id_user', + $config['id_user'] + ), + ] + ); } else { - echo 'status_error'; + echo json_encode( + [ + 'status' => 'status_error', + 'user' => db_get_value( + 'fullname', + 'tusuario', + 'id_user', + $config['id_user'] + ), + ] + ); } return; diff --git a/pandora_console/include/auth/mysql.php b/pandora_console/include/auth/mysql.php index dc0906a36c..638282d381 100644 --- a/pandora_console/include/auth/mysql.php +++ b/pandora_console/include/auth/mysql.php @@ -239,8 +239,7 @@ function process_user_login_remote($login, $pass, $api=false) // Unknown authentication method default: - $config['auth_error'] = 'User not found in database - or incorrect password'; + $config['auth_error'] = 'User not found in database or incorrect password'; return false; break; } diff --git a/pandora_console/include/class/AgentWizard.class.php b/pandora_console/include/class/AgentWizard.class.php index 7f23e84894..aa5acda1ad 100644 --- a/pandora_console/include/class/AgentWizard.class.php +++ b/pandora_console/include/class/AgentWizard.class.php @@ -273,7 +273,7 @@ class AgentWizard extends HTML // Check access. check_login(); - if (! check_acl($config['id_user'], 0, 'AR')) { + if (!check_acl($config['id_user'], 0, 'AR')) { db_pandora_audit( 'ACL Violation', 'Trying to access event viewer' @@ -293,6 +293,29 @@ class AgentWizard extends HTML $this->idAgent = get_parameter('id_agente', ''); $this->idPolicy = get_parameter('id', ''); $this->targetIp = get_parameter('targetIp', ''); + + if (!empty($this->idAgent)) { + $array_aux = db_get_all_rows_sql( + sprintf( + 'SELECT ip FROM taddress ta + INNER JOIN taddress_agent taa ON taa.id_a = ta.id_a + WHERE taa.id_agent = %d', + $this->idAgent + ) + ); + + if (!empty($array_aux)) { + $this->datalist = []; + foreach ($array_aux as $key => $value) { + $this->datalist[] = $value['ip']; + } + } + + if (count($this->datalist) === 1 && $this->targetIp === '') { + $this->targetIp = $this->datalist[0]; + } + } + $this->server = (int) get_parameter('server', '1'); if ($this->server !== 0) { $this->serverType = (int) db_get_value( @@ -563,6 +586,18 @@ class AgentWizard extends HTML ], ]; + if (!empty($this->datalist)) { + $inputs[] = [ + 'id' => 'li_address_list', + 'arguments' => [ + 'name' => 'address_list', + 'type' => 'datalist', + 'value' => $this->datalist, + 'return' => true, + ], + ]; + } + $inputs[] = [ 'label' => __('Target IP'), 'id' => 'txt-targetIp', @@ -573,6 +608,7 @@ class AgentWizard extends HTML 'class' => '', 'value' => $this->targetIp, 'return' => true, + 'list' => 'address_list', ], ]; @@ -865,7 +901,6 @@ class AgentWizard extends HTML ], true ); - } @@ -992,10 +1027,51 @@ class AgentWizard extends HTML } if ($this->wizardSection === 'snmp_interfaces_explorer') { - // First, try x64 interfaces. - $this->interfacesx64 = true; + // Check if thereis x64 counters. + $snmp_tmp = '.1.3.6.1.2.1.31.1.1.1.6'; + $check_x64 = get_snmpwalk( + $this->targetIp, + $this->version, + $this->community, + $this->authUserV3, + $this->securityLevelV3, + $this->authMethodV3, + $this->authPassV3, + $this->privacyMethodV3, + $this->privacyPassV3, + 0, + $snmp_tmp, + $this->targetPort, + $this->server, + $this->extraArguments + ); + + if ($check_x64) { + $this->interfacesx64 = true; + $oidExplore = '.1.3.6.1.2.1.31.1.1.1.1'; + } else { + $this->interfacesx64 = false; + $oidExplore = '1.3.6.1.2.1.2.2.1.2'; + } + // Explore interface names. $oidExplore = '.1.3.6.1.2.1.31.1.1.1.1'; + $receivedOid = get_snmpwalk( + $this->targetIp, + $this->version, + $this->community, + $this->authUserV3, + $this->securityLevelV3, + $this->authMethodV3, + $this->authPassV3, + $this->privacyMethodV3, + $this->privacyPassV3, + 0, + $oidExplore, + $this->targetPort, + $this->server, + $this->extraArguments + ); } else { // Get the device PEN. $oidExplore = '.1.3.6.1.2.1.1.2.0'; @@ -1310,7 +1386,7 @@ class AgentWizard extends HTML * * @return array */ - public function candidateModuleToCreate(array $data):array + public function candidateModuleToCreate(array $data): array { $modulesActivated = []; $generalInterface = false; @@ -1391,10 +1467,16 @@ class AgentWizard extends HTML $result[$value]['name'] = $data['module-default_name-'.$key]; } else if (empty(preg_match('/module-description-set/', $k)) === false) { $result[$value]['description'] = $data['module-default_description-'.$key]; + } else if (empty(preg_match('/module-value/', $k)) === false) { + $result[$value]['value'] = $data['module-value-'.$key]; } - preg_match('/^(.*)-.*?_(\d-\d)$/', $k, $matches); + preg_match('/^(.*)-.*?_(\d+-\d+)$/', $k, $matches); $k = $matches[1].'-0_'.$matches[2]; + } else { + if (empty(preg_match('/module-value/', $k)) === false) { + $result[$value]['value'] = $data[$k]; + } } } @@ -1418,7 +1500,7 @@ class AgentWizard extends HTML $result[$value]['scan_type'] = (int) $data[$k]; } else if (empty(preg_match('/module-execution_type/', $k)) === false) { $result[$value]['execution_type'] = (int) $data[$k]; - } else if (empty(preg_match('/module-value/', $k)) === false) { + } else if (($data['wizard_section'] !== 'snmp_interfaces_explorer') && (empty(preg_match('/module-value/', $k)) === false)) { $result[$value]['value'] = $data[$k]; } else if (empty(preg_match('/module-macros/', $k)) === false) { $result[$value]['macros'] = $data[$k]; @@ -1560,8 +1642,8 @@ class AgentWizard extends HTML if ($this->securityLevelV3 === 'authNoPriv' || $this->securityLevelV3 === 'authPriv' ) { - $values['plugin_parameter'] = $this->authMethodV3; - $values['plugin_pass'] = $this->authPassV3; + $values['plugin_parameter'] = $this->authMethodV3; + $values['plugin_pass'] = $this->authPassV3; if ($this->securityLevelV3 === 'authPriv') { $values['custom_string_1'] = $this->privacyMethodV3; $values['custom_string_2'] = $this->privacyPassV3; @@ -2261,7 +2343,7 @@ class AgentWizard extends HTML private function replacementMacrosPlugin( string $text, array $macros - ):string { + ): string { // Only agents. if (empty($this->idPolicy) === true) { // Common. @@ -2308,7 +2390,7 @@ class AgentWizard extends HTML ?string $value, ?string $unit='', ?int $moduleType=0 - ):string { + ): string { if ($moduleType !== MODULE_TYPE_REMOTE_SNMP_INC && $moduleType !== MODULE_TYPE_GENERIC_DATA_INC && $moduleType !== MODULE_TYPE_REMOTE_TCP_INC @@ -2562,7 +2644,7 @@ class AgentWizard extends HTML // Unpack the extra fields // and include with key field in a field set. $macros = json_decode($module['macros'], true); - $fieldSet = [ '0' => $module['query_key_field'] ]; + $fieldSet = ['0' => $module['query_key_field']]; foreach ($macros as $fieldKey => $fieldMacro) { if (preg_match('/extra_field_/', $fieldKey) !== 0) { $tmpKey = explode('_', $fieldKey); @@ -3100,7 +3182,6 @@ class AgentWizard extends HTML // Add Create Modules form. $this->createModulesForm(); } - } @@ -3209,7 +3290,6 @@ class AgentWizard extends HTML } return false; - } @@ -3306,7 +3386,7 @@ class AgentWizard extends HTML * * @return array Inputs for common data. */ - private function getCommonDataInputs():array + private function getCommonDataInputs(): array { $inputs[] = [ 'id' => 'create-modules-action', @@ -4116,13 +4196,13 @@ class AgentWizard extends HTML } - /** - * This function return the definition of modules for SNMP Interfaces - * - * @param array $data Data. - * - * @return array Return modules for defect. - */ + /** + * This function return the definition of modules for SNMP Interfaces + * + * @param array $data Data. + * + * @return array Return modules for defect. + */ private function getInterfacesModules(array $data=[]) { $moduleDescription = ''; @@ -4207,6 +4287,34 @@ class AgentWizard extends HTML ], ]; + // Get x86 or x64 modules. + if ($this->interfacesx64 === true) { + $definition_temp = $this->getInterfacesModulesx64($data); + } else { + $definition_temp = $this->getInterfacesModulesx86($data); + } + + // General monitoring names. + $general_module_names = [ + 'ifInOctets / ifHCInOctets', + 'ifOutOctets / ifHCOutOctets', + 'ifInUcastPkts / ifHCInUcastPkts', + 'ifOutUcastPkts / ifHCOutUcastPkts', + 'ifInNUcastPkts / ifHCInNUcastPkts', + 'ifOutNUcastPkts / ifHCOutNUcastPkts', + ]; + + if ($name == '') { + foreach ($definition_temp as $module => $module_def) { + $definition_temp[$module]['module_name'] = array_shift($general_module_names); + } + } + + if (empty($definition_temp) === false) { + $definition = array_merge($definition, $definition_temp); + } + + // Continue with common x86 and x84 modules. // IfAdminStatus. $moduleName = $name.'ifAdminStatus'; $definition['ifAdminStatus'] = [ @@ -4333,19 +4441,6 @@ class AgentWizard extends HTML ], ]; - // Get x86 or x64 modules. - if ($this->interfacesx64 === true) { - $definitionx64 = $this->getInterfacesModulesx64($data); - if (empty($definitionx64) === false) { - $definition = array_merge($definition, $definitionx64); - } - } else { - $definitionx86 = $this->getInterfacesModulesx86($data); - if (empty($definitionx86) === false) { - $definition = array_merge($definition, $definitionx86); - } - } - return $definition; } @@ -4815,7 +4910,7 @@ class AgentWizard extends HTML try { exec($execution, $output); } catch (Exception $ex) { - $output = [ '0' => 'ERROR: Failed execution: '.(string) $ex]; + $output = ['0' => 'ERROR: Failed execution: '.(string) $ex]; } return $output; @@ -4913,7 +5008,7 @@ class AgentWizard extends HTML // Meta. var meta = "<?php echo is_metaconsole(); ?>"; var hack_meta = ''; - if(meta){ + if (meta) { hack_meta = '../../'; } @@ -4921,15 +5016,15 @@ class AgentWizard extends HTML showV3Form(); // Filter search interfaces snmp. - $('#text-filter-search').keyup(function () { + $('#text-filter-search').keyup(function() { var string = $('#text-filter-search').val(); var regex = new RegExp(string); var interfaces = $('.interfaces_search'); - interfaces.each(function(){ - if(string == ''){ + interfaces.each(function() { + if (string == '') { $(this).removeClass('hidden'); } else { - if(this.id.match(regex)) { + if (this.id.match(regex)) { $(this).removeClass('hidden'); } else { $(this).addClass('hidden'); @@ -4939,12 +5034,12 @@ class AgentWizard extends HTML }); // Loading. - $('#submit-sub-protocol').click(function () { + $('#submit-sub-protocol').click(function() { $('.wizard-result').remove(); $('#form-create-modules').remove(); $('.textodialogo').remove(); $('.loading-wizard') - .html('<center><span style="font-size:25px;">Loading...</span><img style="width:25px;heigth:25px;" src="'+hack_meta+'images/spinner.gif"></center>'); + .html('<center><span style="font-size:25px;">Loading...</span><img style="width:25px;heigth:25px;" src="' + hack_meta + 'images/spinner.gif"></center>'); }); }); @@ -4962,17 +5057,17 @@ class AgentWizard extends HTML function showSecurityLevelForm() { var selector = $('#securityLevelV3').val(); - if(selector === 'authNoPriv' || selector === 'authPriv'){ + if (selector === 'authNoPriv' || selector === 'authPriv') { $('#txt-authMethodV3').removeClass('invisible'); $('#txt-authPassV3').removeClass('invisible'); - if(selector === 'authPriv'){ + if (selector === 'authPriv') { $('#txt-privacyMethodV3').removeClass('invisible'); $('#txt-privacyPassV3').removeClass('invisible'); } else { $('#txt-privacyMethodV3').addClass('invisible'); $('#txt-privacyPassV3').addClass('invisible'); } - } else { + } else { $('#txt-authMethodV3').addClass('invisible'); $('#txt-authPassV3').addClass('invisible'); $('#txt-privacyMethodV3').addClass('invisible'); @@ -4986,45 +5081,42 @@ class AgentWizard extends HTML var text = ""; var failed = 0; try { - data = JSON.parse(data); - text = data["result"]; + data = JSON.parse(data); + text = data["result"]; } catch (err) { - title = "<?php echo __('Failed'); ?>"; - text = err.message; - failed = 1; + title = "<?php echo __('Failed'); ?>"; + text = err.message; + failed = 1; } if (!failed && data["error"] != undefined) { - title = "<?php echo __('Failed'); ?>"; - text = data["error"]; - failed = 1; + title = "<?php echo __('Failed'); ?>"; + text = data["error"]; + failed = 1; } if (data["report"] != undefined) { - data["report"].forEach(function(item) { - text += "<br>" + item; - }); + data["report"].forEach(function(item) { + text += "<br>" + item; + }); } $("#msg").empty(); $("#msg").html(text); $("#msg").dialog({ - width: 450, - position: { - my: "center", - at: "center", - of: window, - collision: "fit" - }, - title: title, - buttons: [ - { - class: - "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", + width: 450, + position: { + my: "center", + at: "center", + of: window, + collision: "fit" + }, + 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) { $("#msg").close(); } - } - ] + }] }); } @@ -5044,8 +5136,8 @@ class AgentWizard extends HTML var markedCount = 0; if (type == 'block') { selectedBlock - .parent() - .removeClass("alpha50"); + .parent() + .removeClass("alpha50"); if (selectedBlock.prop("checked")) { // Set to active the values of fields. $("[id*=hidden-module-active-"+blockNumber+"]") @@ -5054,9 +5146,9 @@ class AgentWizard extends HTML }); // Set checked. $("[id*=checkbox-sel_module_" + blockNumber + "]") - .each(function(){ - $(this).prop("checked", true); - }); + .each(function() { + $(this).prop("checked", true); + }); imageInfoModules.removeClass('hidden'); } else { // Set to inactive the values of fields. @@ -5066,15 +5158,15 @@ class AgentWizard extends HTML }); // Set unchecked. $("[id*=checkbox-sel_module_" + blockNumber + "]") - .each(function(){ - $(this).prop("checked", false); - }); + .each(function() { + $(this).prop("checked", false); + }); imageInfoModules.addClass('hidden'); } } else if (type == 'module') { // Getting the element. - var thisModuleHidden = document.getElementById("hidden-module-active-"+switchName[2]+"_"+moduleNumber); - var thisModule = $("#checkbox-sel_module_"+blockNumber+"_"+moduleNumber); + var thisModuleHidden = document.getElementById("hidden-module-active-" + switchName[2] + "_" + moduleNumber); + var thisModule = $("#checkbox-sel_module_" + blockNumber + "_" + moduleNumber); // Setting the individual field if (thisModule.prop('checked')) { thisModuleHidden.value = '1'; @@ -5084,12 +5176,12 @@ class AgentWizard extends HTML // Get the list of selected modules. $("[id*=checkbox-sel_module_" + blockNumber + "]") - .each(function() { - if ($(this).prop("checked")) { - markedCount++; - } - totalCount++; - }); + .each(function() { + if ($(this).prop("checked")) { + markedCount++; + } + totalCount++; + }); if (totalCount == markedCount) { selectedBlock.prop("checked", true); @@ -5118,7 +5210,7 @@ class AgentWizard extends HTML */ function switchBlockControlInterfaces(e) { var string = $('#text-filter-search').val(); - if(string == ''){ + if (string == '') { if (e.checked) { $(".interfaz_select").prop("checked", true); } else { @@ -5127,15 +5219,15 @@ class AgentWizard extends HTML } else { var regex = new RegExp(string); var interfaces = $('.interfaces_search'); - interfaces.each(function(){ - if(this.id.match(regex)) { + interfaces.each(function() { + if (this.id.match(regex)) { $(this).removeClass('hidden'); if (e.checked) { - $("input[name='interfaz_select_"+this.id+"']") + $("input[name='interfaz_select_" + this.id + "']") .prop("checked", true); } else { - $("input[name='interfaz_select_"+this.id+"']") - .prop("checked", false); + $("input[name='interfaz_select_" + this.id + "']") + .prop("checked", false); } } }); @@ -5143,13 +5235,13 @@ class AgentWizard extends HTML } /** - * Show the modal with modules for create. - */ + * Show the modal with modules for create. + */ function processListModules() { confirmDialog({ title: "<?php echo __('Modules about to be created'); ?>", message: function() { - var id = "div-"+uniqId(); + var id = "div-" + uniqId(); var loading = "<?php echo __('Loading'); ?>" + "..."; $.ajax({ method: "post", @@ -5165,22 +5257,22 @@ class AgentWizard extends HTML }, datatype: "html", success: function(data) { - $('#'+id).empty().append(data); + $('#' + id).empty().append(data); }, error: function(e) { showMsg(e); } }); - return "<div id ='"+id+"'>"+loading+"</div>"; + return "<div id ='" + id + "'>" + loading + "</div>"; }, ok: "<?php echo __('OK'); ?>", cancel: "<?php echo __('Cancel'); ?>", onAccept: function() { - $('#reviewed-modules').submit(); + $('#reviewed-modules').submit(); }, - size:750, - maxHeight:500 + size: 750, + maxHeight: 500 }); } diff --git a/pandora_console/include/class/CredentialStore.class.php b/pandora_console/include/class/CredentialStore.class.php index 073f0831a3..d14314a6b4 100644 --- a/pandora_console/include/class/CredentialStore.class.php +++ b/pandora_console/include/class/CredentialStore.class.php @@ -248,7 +248,7 @@ class CredentialStore extends Wizard ); } else { $groups = [ $filter['filter_id_group'] ]; - $childrens = groups_get_childrens($id_group, null, true); + $childrens = groups_get_children($id_group, null, true); if (!empty($childrens)) { foreach ($childrens as $child) { $groups[] = (int) $child['id_grupo']; diff --git a/pandora_console/include/class/HTML.class.php b/pandora_console/include/class/HTML.class.php index 376afc4bfd..41ceabf5ab 100644 --- a/pandora_console/include/class/HTML.class.php +++ b/pandora_console/include/class/HTML.class.php @@ -547,6 +547,7 @@ class HTML } else { if ($input['arguments']['type'] != 'hidden' && $input['arguments']['type'] != 'hidden_extended' + && $input['arguments']['type'] != 'datalist' ) { if (!$direct) { $output .= '<li id="'.$input['id'].'" class="'.$class.'">'; diff --git a/pandora_console/include/class/NetworkMap.class.php b/pandora_console/include/class/NetworkMap.class.php index a14e2b80c4..0eaea52134 100644 --- a/pandora_console/include/class/NetworkMap.class.php +++ b/pandora_console/include/class/NetworkMap.class.php @@ -810,7 +810,7 @@ class NetworkMap $filter['id_grupo'] = $this->idGroup; } else { // Show current group and children. - $childrens = groups_get_childrens($this->idGroup, null, true); + $childrens = groups_get_children($this->idGroup, null, true); if (!empty($childrens)) { $childrens = array_keys($childrens); diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index e490b8d671..72332b699e 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC201029'; +$build_version = 'PC201123'; $pandora_version = 'v7.0NG.750'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index d32dacb1fe..258b6e805c 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -309,7 +309,7 @@ define('STATUS_ALERT_DISABLED', 'alert_disabled.png'); // For servers. define('STATUS_SERVER_OK', 'server_ok.png'); define('STATUS_SERVER_DOWN', 'server_down.png'); - +define('STATUS_SERVER_CRASH', 'server_crash.png'); // Status images (ball). @@ -335,6 +335,7 @@ define('STATUS_ALERT_DISABLED_BALL', 'alert_disabled_ball.png'); // For servers. define('STATUS_SERVER_OK_BALL', 'server_ok_ball.png'); define('STATUS_SERVER_DOWN_BALL', 'server_down_ball.png'); +define('STATUS_SERVER_CRASH_BALL', 'server_crash_ball.png'); diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index a033f33115..a67379b07d 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -1342,6 +1342,73 @@ function get_priority_name($priority) } +/** + * Translates status into string. + * + * @param integer $status Agent status. + * + * @return string Translation. + */ +function get_agent_status_string($status) +{ + switch ($status) { + case AGENT_STATUS_CRITICAL: + return __('CRITICAL'); + + case AGENT_STATUS_WARNING: + return __('WARNING'); + + case AGENT_STATUS_ALERT_FIRED: + return __('ALERT FIRED'); + + case AGENT_STATUS_NOT_INIT: + return __('NO DATA'); + + case AGENT_STATUS_NORMAL: + return __('NORMAL'); + + case AGENT_STATUS_UNKNOWN: + default: + return __('UNKNOWN'); + } +} + + +/** + * Translates status into string. + * + * @param integer $status Module status. + * + * @return string Translation. + */ +function get_module_status_string($status) +{ + switch ($status) { + case AGENT_MODULE_STATUS_CRITICAL_BAD: + return __('CRITICAL'); + + case AGENT_MODULE_STATUS_WARNING_ALERT: + case AGENT_MODULE_STATUS_CRITICAL_ALERT: + return __('ALERT FIRED'); + + case AGENT_MODULE_STATUS_WARNING: + return __('WARNING'); + + case AGENT_MODULE_STATUS_UNKNOWN: + return __('UNKNOWN'); + + case AGENT_MODULE_STATUS_NO_DATA: + case AGENT_MODULE_STATUS_NOT_INIT: + return __('NO DATA'); + + case AGENT_MODULE_STATUS_NORMAL_ALERT: + case AGENT_MODULE_STATUS_NORMAL: + default: + return __('NORMAL'); + } +} + + /** * Get priority class (CSS class) from priority value. * diff --git a/pandora_console/include/functions_agents.php b/pandora_console/include/functions_agents.php index 119852f1b9..45ba5387ba 100644 --- a/pandora_console/include/functions_agents.php +++ b/pandora_console/include/functions_agents.php @@ -19,17 +19,18 @@ require_once $config['homedir'].'/include/functions.php'; require_once $config['homedir'].'/include/functions_modules.php'; -require_once $config['homedir'].'/include/functions_users.php';/** - * Return the agent if exists in the DB. - * - * @param integer $id_agent The agent id. - * @param boolean $show_disabled Show the agent found althought it is disabled. By default false. - * @param boolean $force_meta - * - * @return boolean The result to check if the agent is in the DB. - */ +require_once $config['homedir'].'/include/functions_users.php'; +/** + * Return the agent if exists in the DB. + * + * @param integer $id_agent The agent id. + * @param boolean $show_disabled Show the agent found althought it is disabled. By default false. + * @param boolean $force_meta + * + * @return boolean The result to check if the agent is in the DB. + */ function agents_get_agent($id_agent, $show_disabled=true, $force_meta=false) { $agent = db_get_row_filter( @@ -1113,11 +1114,14 @@ function agents_get_group_agents( foreach ($id_group as $parent) { $id_group = array_merge( $id_group, - groups_get_id_recursive($parent, false) + groups_get_children_ids($parent, $noACL) ); } } else { - $id_group = groups_get_id_recursive($id_group, false); + $id_group = array_merge( + [$id_group], + groups_get_children_ids($id_group, $noACL) + ); } // Check available groups for target user only if asking for 'All' group. diff --git a/pandora_console/include/functions_alerts.php b/pandora_console/include/functions_alerts.php index 2566e265be..74a024d866 100644 --- a/pandora_console/include/functions_alerts.php +++ b/pandora_console/include/functions_alerts.php @@ -2871,17 +2871,8 @@ function alerts_get_agent_modules( ); $agent_modules = db_get_all_rows_sql($sql); } else { - $groups = groups_get_children($id_grupo, true); + $groups = groups_get_children_ids($id_grupo, true); if (empty($groups) === false) { - $groups = array_reduce( - $groups, - function ($carry, $item) { - $carry[] = $item['id_grupo']; - return $carry; - }, - [$id_grupo] - ); - $sql = sprintf( 'SELECT distinct(atm.id_agent_module) FROM talert_template_modules atm diff --git a/pandora_console/include/functions_api.php b/pandora_console/include/functions_api.php index 2b96c52978..a7f6ef8c81 100644 --- a/pandora_console/include/functions_api.php +++ b/pandora_console/include/functions_api.php @@ -1973,7 +1973,7 @@ function api_get_all_agents($thrash1, $thrash2, $other, $returnType) $ag_groups = $other['data'][1]; // Recursion. if ($other['data'][6] === '1') { - $ag_groups = groups_get_id_recursive($ag_groups, true); + $ag_groups = groups_get_children_ids($ag_groups, true); } $ag_groups = implode(',', (array) $ag_groups); diff --git a/pandora_console/include/functions_custom_fields.php b/pandora_console/include/functions_custom_fields.php index d1f661e874..c15b0cae95 100644 --- a/pandora_console/include/functions_custom_fields.php +++ b/pandora_console/include/functions_custom_fields.php @@ -367,7 +367,7 @@ function agent_counters_custom_fields($filters) if ($filters['group']) { // Recursion check acl. if ($filters['recursion']) { - $recursion_groups = groups_get_id_recursive($filters['group'], true); + $recursion_groups = groups_get_children_ids($filters['group'], true); if (!users_can_manage_group_all('AR')) { if (isset($user_groups) && is_array($user_groups)) { $groups_intersect = array_intersect($user_groups, $recursion_groups); diff --git a/pandora_console/include/functions_events.php b/pandora_console/include/functions_events.php index 7a337fbdab..33c2309e30 100644 --- a/pandora_console/include/functions_events.php +++ b/pandora_console/include/functions_events.php @@ -673,15 +673,16 @@ function events_update_status($id_evento, $status, $filter=null, $history=false) /** * Retrieve all events filtered. * - * @param array $fields Fields to retrieve. - * @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. - * @param boolean $history Apply on historical table. - * @param boolean $return_sql Return SQL (true) or execute it (false). - * @param string $having Having filter. + * @param array $fields Fields to retrieve. + * @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. + * @param boolean $history Apply on historical table. + * @param boolean $return_sql Return SQL (true) or execute it (false). + * @param string $having Having filter. + * @param boolean $validatedEvents If true, evaluate validated events. * * @return array Events. * @throws Exception On error. @@ -695,7 +696,8 @@ function events_get_all( $sort_field=null, $history=false, $return_sql=false, - $having='' + $having='', + $validatedEvents=false ) { global $config; @@ -871,37 +873,23 @@ function events_get_all( } $groups = $filter['id_group_filter']; - if (isset($groups) && $groups > 0) { - $propagate = db_get_value( - 'propagate', - 'tgrupo', - 'id_grupo', - $groups - ); + if (isset($groups) === true && $groups > 0) { + $children = groups_get_children($groups); - if (!$propagate && isset($groups)) { - $sql_filters[] = sprintf( - ' AND (te.id_grupo = %d OR tasg.id_group = %d)', - $groups, - $groups - ); - } else { - $children = groups_get_children($groups); - $_groups = [ $groups ]; - if (!empty($children)) { - foreach ($children as $child) { - $_groups[] = (int) $child['id_grupo']; - } + $_groups = [ $groups ]; + if (empty($children) === false) { + foreach ($children as $child) { + $_groups[] = (int) $child['id_grupo']; } - - $groups = $_groups; - - $sql_filters[] = sprintf( - ' AND (te.id_grupo IN (%s) OR tasg.id_group IN (%s))', - join(',', $groups), - join(',', $groups) - ); } + + $groups = $_groups; + + $sql_filters[] = sprintf( + ' AND (te.id_grupo IN (%s) OR tasg.id_group IN (%s))', + join(',', $groups), + join(',', $groups) + ); } // Skip system messages if user is not PM. @@ -926,10 +914,20 @@ function events_get_all( break; case EVENT_NO_VALIDATED: + // Show comments in validated events. + $validatedState = ''; + if ($validatedEvents === true) { + $validatedState = sprintf( + 'OR estado = %d', + EVENT_VALIDATE + ); + } + $sql_filters[] = sprintf( - ' AND (estado = %d OR estado = %d)', + ' AND (estado = %d OR estado = %d %s)', EVENT_NEW, - EVENT_PROCESS + EVENT_PROCESS, + $validatedState ); break; } @@ -1258,7 +1256,11 @@ function events_get_all( // Order. $order_by = ''; if (isset($order, $sort_field)) { - $order_by = events_get_sql_order($sort_field, $order); + if (isset($filter['group_rep']) && $filter['group_rep'] == 1) { + $order_by = events_get_sql_order('MAX('.$sort_field.')', $order); + } else { + $order_by = events_get_sql_order($sort_field, $order); + } } // Pagination. @@ -1550,26 +1552,18 @@ function events_get_event($id, $fields=false, $meta=false, $history=false) /** * Retrieve all events ungrouped. * - * @param string $sql_post Sql_post. - * @param integer $offset Offset. - * @param integer $pagination Pagination. - * @param boolean $meta Meta. - * @param boolean $history History. - * @param boolean $total Total. - * @param boolean $history_db History_db. - * @param string $order Order. + * @param string $sql_post Sql_post. + * @param boolean $meta Meta. + * @param boolean $history History. + * @param boolean $returnSql Only Query. * * @return mixed Array of events or false. */ function events_get_events_no_grouped( $sql_post, - $offset=0, - $pagination=1, $meta=false, $history=false, - $total=false, - $history_db=false, - $order='ASC' + $returnSql=false ) { global $config; @@ -1579,7 +1573,11 @@ function events_get_events_no_grouped( $sql .= events_get_secondary_groups_left_join($table); $sql .= $sql_post; - $events = db_get_all_rows_sql($sql, $history_db); + if ($returnSql === true) { + return $sql; + } + + $events = db_get_all_rows_sql($sql, $history); return $events; } @@ -1632,29 +1630,59 @@ function events_get_events_grouped( $event_lj = events_get_secondary_groups_left_join($table); if ($total) { $sql = "SELECT COUNT(*) FROM (SELECT id_evento - FROM $table te $event_lj - WHERE 1=1 ".$sql_post.' + FROM $table te $event_lj ".$sql_post.' GROUP BY estado, evento, id_agente, id_agentmodule'.$groupby_extra.') AS t'; } else { - $sql = "SELECT *, MAX(id_evento) AS id_evento, - GROUP_CONCAT(DISTINCT user_comment SEPARATOR '<br>') AS user_comment, - GROUP_CONCAT(DISTINCT id_evento SEPARATOR ',') AS similar_ids, - COUNT(id_evento) AS event_rep, MAX(utimestamp) AS timestamp_rep, - MIN(utimestamp) AS timestamp_rep_min, - (SELECT owner_user FROM $table WHERE id_evento = MAX(te.id_evento)) owner_user, - (SELECT id_usuario FROM $table WHERE id_evento = MAX(te.id_evento)) id_usuario, - (SELECT id_agente FROM $table WHERE id_evento = MAX(te.id_evento)) id_agente, - (SELECT criticity FROM $table WHERE id_evento = MAX(te.id_evento)) AS criticity, - (SELECT ack_utimestamp FROM $table WHERE id_evento = MAX(te.id_evento)) AS ack_utimestamp, - (SELECT nombre FROM tagente_modulo WHERE id_agente_modulo = te.id_agentmodule) AS module_name - FROM $table te $event_lj - WHERE 1=1 ".$sql_post.' - GROUP BY estado, evento, id_agente, id_agentmodule'.$groupby_extra; - $sql .= ' '.events_get_sql_order($sort_field, $order, 2); - $sql .= ' LIMIT '.$offset.','.$pagination; + $sql = sprintf( + 'SELECT *, + MAX(id_evento) AS id_evento, + GROUP_CONCAT( + DISTINCT user_comment SEPARATOR "<br>" + ) AS user_comment, + GROUP_CONCAT( + DISTINCT id_evento SEPARATOR "," + ) AS similar_ids, + COUNT(id_evento) AS event_rep, MAX(utimestamp) AS timestamp_rep, + MIN(utimestamp) AS timestamp_rep_min, + (SELECT owner_user + FROM %s + WHERE id_evento = MAX(te.id_evento)) AS owner_user, + (SELECT id_usuario + FROM %s + WHERE id_evento = MAX(te.id_evento)) AS id_usuario, + (SELECT id_agente + FROM %s + WHERE id_evento = MAX(te.id_evento)) AS id_agente, + (SELECT criticity + FROM %s + WHERE id_evento = MAX(te.id_evento)) AS criticity, + (SELECT ack_utimestamp + FROM %s + WHERE id_evento = MAX(te.id_evento)) AS ack_utimestamp, + (SELECT nombre + FROM tagente_modulo + WHERE id_agente_modulo = te.id_agentmodule) AS module_name + FROM %s te %s + %s + GROUP BY estado, evento, id_agente, id_agentmodule %s + %s + LIMIT %d, %d', + $table, + $table, + $table, + $table, + $table, + $table, + $event_lj, + $sql_post, + $groupby_extra, + events_get_sql_order($sort_field, $order, 2), + $offset, + $pagination + ); } - // Extract the events by filter (or not) from db + // Extract the events by filter (or not) from db. $events = db_get_all_rows_sql($sql, $history_db); if ($total) { @@ -2969,7 +2997,8 @@ function events_get_agent( $type = []; foreach ($filter_event_type as $event_type) { if ($event_type != '') { - // If normal, warning, could be several (going_up_warning, going_down_warning... too complex. + // If normal, warning, could be several + // (going_up_warning, going_down_warning... too complex. // Shown to user only "warning, critical and normal". if ($event_type == 'warning' || $event_type == 'critical' || $event_type == 'normal') { $type[] = " event_type LIKE '%".$event_type."%' "; @@ -2989,10 +3018,10 @@ function events_get_agent( } if ($events_group) { - $sql_where .= sprintf( + $secondary_groups = sprintf( ' INNER JOIN tgrupo tg - ON (te.id_grupo = tg.id_grupo AND tg.id_grupo = %s) - OR (tg.id_grupo = tasg.id_group AND tasg.id_group = %s) + ON (te.id_grupo = tg.id_grupo AND tg.id_grupo IN (%s)) + OR (tg.id_grupo = tasg.id_group AND tasg.id_group IN (%s)) WHERE utimestamp > %d AND utimestamp <= %d ', join(',', $id_group), @@ -3000,22 +3029,27 @@ function events_get_agent( $datelimit, $date ); - } else if ($events_module) { - $sql_where .= sprintf( - ' AND id_agentmodule = %d AND utimestamp > %d - AND utimestamp <= %d ', - $id_agent_module, - $datelimit, - $date - ); + $sql_where = $secondary_groups.' '.$sql_where; } else { - $sql_where .= sprintf( - ' AND id_agente = %d AND utimestamp > %d - AND utimestamp <= %d ', - $id_agent, - $datelimit, - $date - ); + $sql_where = ' WHERE 1=1 '.$sql_where; + + if ($events_module) { + $sql_where .= sprintf( + ' AND id_agentmodule = %d AND utimestamp > %d + AND utimestamp <= %d ', + $id_agent_module, + $datelimit, + $date + ); + } else { + $sql_where .= sprintf( + ' AND id_agente = %d AND utimestamp > %d + AND utimestamp <= %d ', + $id_agent, + $datelimit, + $date + ); + } } if (is_metaconsole() && $id_server) { @@ -3035,11 +3069,7 @@ function events_get_agent( } else { return events_get_events_no_grouped( $sql_where, - 0, - 1000, (is_metaconsole() && $id_server) ? true : false, - false, - false, $history ); } @@ -3692,6 +3722,38 @@ function events_get_response_target( $event_response = db_get_row('tevent_response', 'id', $response_id); $target = io_safe_output($event_response['target']); + if (strpos($target, '_agent_alias_') !== false) { + if ($meta) { + $agente_table_name = 'tmetaconsole_agent'; + $filter = [ + 'id_tagente' => $event['id_agente'], + 'id_tmetaconsole_setup' => $server_id, + ]; + } else { + $agente_table_name = 'tagente'; + $filter = ['id_agente' => $event['id_agente']]; + } + + $alias = db_get_value_filter('alias', $agente_table_name, $filter); + $target = str_replace('_agent_alias_', io_safe_output($alias), $target); + } + + if (strpos($target, '_agent_name_') !== false) { + if ($meta) { + $agente_table_name = 'tmetaconsole_agent'; + $filter = [ + 'id_tagente' => $event['id_agente'], + 'id_tmetaconsole_setup' => $server_id, + ]; + } else { + $agente_table_name = 'tagente'; + $filter = ['id_agente' => $event['id_agente']]; + } + + $name = db_get_value_filter('nombre', $agente_table_name, $filter); + $target = str_replace('_agent_name_', io_safe_output($name), $target); + } + // Substitute each macro. if (strpos($target, '_agent_address_') !== false) { if ($meta) { @@ -3771,7 +3833,7 @@ function events_get_response_target( if (strpos($target, '_group_name_') !== false) { $target = str_replace( '_group_name_', - groups_get_name($event['id_grupo'], true), + io_safe_output(groups_get_name($event['id_grupo'], true)), $target ); } @@ -3787,7 +3849,7 @@ function events_get_response_target( if (strpos($target, '_event_date_') !== false) { $target = str_replace( '_event_date_', - date($config['date_format'], $event['utimestamp']), + io_safe_output(date($config['date_format'], $event['utimestamp'])), $target ); } @@ -3811,7 +3873,7 @@ function events_get_response_target( if (strpos($target, '_alert_id_') !== false) { $target = str_replace( '_alert_id_', - empty($event['is_alert_am']) ? __('N/A') : $event['is_alert_am'], + empty($event['id_alert_am']) ? __('N/A') : $event['id_alert_am'], $target ); } @@ -3893,6 +3955,15 @@ function events_get_response_target( $target = str_replace('_current_user_', $config['id_user'], $target); } + // This will replace the macro with the command timeout value. + if (strpos($target, '_command_timeout_') !== false) { + $target = str_replace( + '_command_timeout_', + $event_response['command_timeout'], + $target + ); + } + return $target; } @@ -4630,16 +4701,24 @@ function events_page_general($event) $table_general->data[] = $data; // If event is validated, show who and when acknowleded it. + $table_general->cellclass[8][1] = 'general_acknowleded'; + $data = []; $data[0] = __('Acknowledged by'); if ($event['estado'] == 1) { - $user_ack = db_get_value('fullname', 'tusuario', 'id_user', $event['id_usuario']); - if (empty($user_ack)) { + $user_ack = db_get_value( + 'fullname', + 'tusuario', + 'id_user', + $event['id_usuario'] + ); + + if (empty($user_ack) === true) { $user_ack = $event['id_usuario']; } - $date_ack = date($config['date_format'], $event['ack_utimestamp']); + $date_ack = io_safe_output($event['ack_utimestamp']); $data[1] = $user_ack.' ('.$date_ack.')'; } else { $data[1] = '<i>'.__('N/A').'</i>'; @@ -6973,7 +7052,7 @@ function events_get_field_value_by_event_id( if (strpos($value, '_group_name_') !== false) { $value = str_replace( '_group_name_', - groups_get_name($event['id_grupo'], true), + io_safe_output(groups_get_name($event['id_grupo'], true)), $value ); } @@ -6989,7 +7068,9 @@ function events_get_field_value_by_event_id( if (strpos($value, '_event_date_') !== false) { $value = str_replace( '_event_date_', - date($config['date_format'], $event['utimestamp']), + io_safe_output( + date($config['date_format'], $event['utimestamp']) + ), $value ); } diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index 4fd1439f8f..f40b75e3b2 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -2541,13 +2541,9 @@ function graphic_agentaccess( } else { $options['generals']['pdf']['width'] = 350; $options['generals']['pdf']['height'] = 125; - if (!empty($data_array)) { - $imgbase64 = '<img src="data:image/jpg;base64,'; - $imgbase64 .= vbar_graph($data_array, $options, 2); - $imgbase64 .= '" />'; - } else { - $imgbase64 .= vbar_graph($data_array, $options, 2); - } + $imgbase64 = '<img src="data:image/jpg;base64,'; + $imgbase64 .= vbar_graph($data_array, $options, 2); + $imgbase64 .= '" />'; return $imgbase64; } diff --git a/pandora_console/include/functions_groups.php b/pandora_console/include/functions_groups.php index b6c1a5e6c9..bfbf8b5193 100644 --- a/pandora_console/include/functions_groups.php +++ b/pandora_console/include/functions_groups.php @@ -104,7 +104,7 @@ function groups_check_used($idGroup) if ($numRows > 0) { $return['return'] = true; - $return['tables'][] = __('Recon task'); + $return['tables'][] = __('Discovery task'); } switch ($config['dbtype']) { @@ -266,48 +266,25 @@ function groups_check_used($idGroup) /** - * Return a array of id_group of childrens (to branches down) - * - * @param integer $parent The id_group parent to search the childrens. - * @param array $groups The groups, its for optimize the querys to DB. - */ -function groups_get_childrens_ids($parent, $groups=null) -{ - if (empty($groups)) { - $groups = db_get_all_rows_in_table('tgrupo'); - } - - $return = ''; - - foreach ($groups as $key => $group) { - if ($group['id_grupo'] == 0) { - continue; - } - - if ($group['parent'] == $parent) { - $return .= $group['id_grupo'].','; - $propagate = db_get_value('propagate', 'tgrupo', 'id_grupo', $group['id_grupo']); - if ($propagate) { - $return .= groups_get_childrens_ids($group['id_grupo']); - } - } - } - - return $return; -} - - -/** - * Return a array of id_group of children of given parent. + * Return a array of id_group of children of given parent INCLUDING PARENT!!. * * @param integer $parent The id_grupo parent to search its children. * @param array $ignorePropagate Ignore propagate. + * @param string $privilege Default privilege. + * @param boolean $selfInclude Include group "id_parent" in return. + * + * @return array Of Groups, children of $parent. */ -function groups_get_children($parent, $ignorePropagate=false) -{ +function groups_get_children( + $parent, + $ignorePropagate=false, + $privilege='AR', + $selfInclude=true +) { static $groups; + static $user_groups; - if (empty($groups)) { + if (empty($groups) === true) { $aux_groups = []; $groups = db_get_all_rows_in_table('tgrupo'); foreach ($groups as $key => $value) { @@ -317,19 +294,45 @@ function groups_get_children($parent, $ignorePropagate=false) $groups = $aux_groups; } + if (empty($user_groups) === true) { + $user_groups = users_get_groups(false, $privilege, true); + } + + // Admin see always all groups. + $ignorePropagate = users_is_admin() || $ignorePropagate; + + // Prepare array. $return = []; + + if ($selfInclude === true) { + if (array_key_exists($parent, $user_groups) === true) { + $return[$parent] = $groups[$parent]; + } + } + foreach ($groups as $key => $g) { if ($g['id_grupo'] == 0) { continue; } - if ($ignorePropagate || $parent == 0 || $groups[$parent]['propagate']) { + // IgnorePropagate will be true if user can access child. + $allowed = $ignorePropagate || array_key_exists( + $g['id_grupo'], + $user_groups + ); + + if ($allowed === true + || (int) $parent === 0 + || (bool) $groups[$parent]['propagate'] === true + ) { if ($g['parent'] == $parent) { $return += [$g['id_grupo'] => $g]; if ($g['propagate'] || $ignorePropagate) { $return += groups_get_children( $g['id_grupo'], - $ignorePropagate + $ignorePropagate, + $privilege, + $selfInclude ); } } @@ -340,38 +343,6 @@ function groups_get_children($parent, $ignorePropagate=false) } -/** - * @deprecated This is not working. Expects 'propagate' on CHILD not on PARENT!!! - * - * Return a array of id_group of childrens (to branches down) - * - * @param integer $parent The id_group parent to search the childrens. - * @param array $groups The groups, its for optimize the querys to DB. - */ -function groups_get_childrens($parent, $groups=null, $onlyPropagate=false) -{ - if (empty($groups)) { - $groups = db_get_all_rows_in_table('tgrupo'); - } - - $return = []; - - foreach ($groups as $key => $group) { - if ($group['id_grupo'] == 0) { - continue; - } - - if ($group['propagate'] || $onlyPropagate) { - if ($group['parent'] == $parent) { - $return = ($return + [$group['id_grupo'] => $group] + groups_get_childrens($group['id_grupo'], $groups, $onlyPropagate)); - } - } - } - - return $return; -} - - /** * Return a array of id_group of parents (to roots up). * @@ -534,42 +505,30 @@ function groups_get_all($groupWithAgents=false) /** - * Get all groups recursive from an initial group. + * Get all groups recursive from an initial group INCLUDING PARENT!!. * - * @param int Id of the parent group - * @param bool Whether to force recursive search ignoring propagation (true) or not (false) + * @param integer $id_parent Id of the parent group. + * @param boolean $ignorePropagate Whether to force recursive search ignoring + * propagation (true) or not (false). + * @param boolean $selfInclude Include group "id_parent" in return. + * @param string $privilege Privilege flag to search for default 'AR'. * - * @return array with all result groups + * @return array With all result groups. */ -function groups_get_id_recursive($id_parent, $all=false) -{ - $return = []; +function groups_get_children_ids( + $id_parent, + $ignorePropagate=false, + $selfInclude=true, + $privilege='AR' +) { + $return = groups_get_children( + $id_parent, + $ignorePropagate, + $privilege, + $selfInclude + ); - $return = array_merge($return, [$id_parent]); - - // Check propagate - $propagate = db_get_value_filter('propagate', 'tgrupo', ['id_grupo' => $id_parent]); - - if (($propagate == 1) || $all) { - $children = db_get_all_rows_filter('tgrupo', ['parent' => $id_parent, 'disabled' => 0], ['id_grupo']); - - if ($children === false) { - $children = []; - } else { - $temp = []; - foreach ($children as $id_children) { - $temp = array_merge($temp, [$id_children['id_grupo']]); - } - - $children = $temp; - } - - foreach ($children as $id_children) { - $return = array_merge($return, groups_get_id_recursive($id_children, $all)); - } - } - - return $return; + return array_keys($return); } diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 7ffbda2417..bda3a759e0 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -519,7 +519,15 @@ function html_print_select_groups( } } else { foreach ($selected as $k) { - $fields[$k] = groups_get_name($k); + if ($k === null || $k === '') { + continue; + } + + $fields[$k] = groups_get_name($k, $returnAllGroup); + } + + if (empty($fields) === true && $returnAllGroup) { + $fields[0] = groups_get_name(null, true); } } @@ -2024,6 +2032,7 @@ function html_print_input_text_extended( 'required', 'autocomplete', 'form', + 'list', ]; $output = '<input '.($password ? 'type="password" autocomplete="'.$autocomplete.'" ' : 'type="text" '); @@ -2298,7 +2307,8 @@ function html_print_input_text( $onKeyDown='', $formTo='', $onKeyUp='', - $disabled=false + $disabled=false, + $list='' ) { if ($maxlength == 0) { $maxlength = 255; @@ -2343,6 +2353,10 @@ function html_print_input_text( $attr['form'] = $formTo; } + if ($list != '') { + $attr['list'] = $list; + } + return html_print_input_text_extended( $name, $value, @@ -4283,7 +4297,9 @@ function html_print_input($data, $wrapper='div', $input_only=false) ((isset($data['autofocus']) === true) ? $data['autofocus'] : false), ((isset($data['onKeyDown']) === true) ? $data['onKeyDown'] : ''), ((isset($data['form']) === true) ? $data['form'] : ''), - ((isset($data['onKeyUp']) === true) ? $data['onKeyUp'] : '') + ((isset($data['onKeyUp']) === true) ? $data['onKeyUp'] : ''), + ((isset($data['disabled']) === true) ? $data['disabled'] : false), + ((isset($data['list']) === true) ? $data['list'] : '') ); break; @@ -4780,6 +4796,14 @@ function html_print_input($data, $wrapper='div', $input_only=false) $output .= html_print_select_multiple_modules_filtered($data); break; + case 'datalist': + $output .= html_print_datalist( + $data['name'], + $data['value'], + ((isset($data['return']) === true) ? $data['return'] : true) + ); + break; + default: // Ignore. break; @@ -4960,3 +4984,32 @@ function html_print_tabs(array $tabs) return $result; } + + +/** + * Create a datalist. + * + * @param string $id Use custom id. + * @param string $values Input values. + * @param string $returnparam Whether to return an output string or echo now (optional, echo by default). + * + * @return string HTML code if return parameter is true. + */ +function html_print_datalist( + $id, + $values, + $return=false +) { + $result = '<datalist id="'.$id.'">'; + foreach ($values as $key => $value) { + $result .= '<option value="'.$value.'">'; + } + + $result .= '</datalist>'; + + if ($return) { + return $result; + } else { + echo $result; + } +} diff --git a/pandora_console/include/functions_io.php b/pandora_console/include/functions_io.php index 6390f78f96..336e9480dd 100755 --- a/pandora_console/include/functions_io.php +++ b/pandora_console/include/functions_io.php @@ -116,6 +116,13 @@ function io_safe_input($value) // TICKET: 1223 $valueHtmlEncode = str_replace('°', '°', $valueHtmlEncode); + // Fixed the ¿ charater. + $valueHtmlEncode = str_replace('¿', '¿', $valueHtmlEncode); + // Fixed the ¡ charater. + $valueHtmlEncode = str_replace('¡', '¡', $valueHtmlEncode); + // Fixed the € charater. + $valueHtmlEncode = str_replace('€', '€', $valueHtmlEncode); + // Replace some characteres for html entities for ($i = 0; $i < 33; $i++) { $valueHtmlEncode = str_ireplace( diff --git a/pandora_console/include/functions_modules.php b/pandora_console/include/functions_modules.php index 9a5ea93f92..e28c255f9c 100755 --- a/pandora_console/include/functions_modules.php +++ b/pandora_console/include/functions_modules.php @@ -2494,6 +2494,8 @@ function modules_get_color_status($status, $force_module=false) case STATUS_AGENT_CRITICAL: case STATUS_MODULE_CRITICAL_BALL: case STATUS_AGENT_CRITICAL_BALL: + case STATUS_SERVER_CRASH: + case STATUS_SERVER_CRASH_BALL: return COL_CRITICAL; case AGENT_MODULE_STATUS_WARNING: diff --git a/pandora_console/include/functions_networkmap.php b/pandora_console/include/functions_networkmap.php index 56172331c6..bd5152576d 100644 --- a/pandora_console/include/functions_networkmap.php +++ b/pandora_console/include/functions_networkmap.php @@ -319,7 +319,7 @@ function networkmap_generate_dot( if ($dont_show_subgroups) { $filter['id_grupo'] = $group; } else { - $childrens = groups_get_childrens($group, null, true); + $childrens = groups_get_children($group, null, true); if (!empty($childrens)) { $childrens = array_keys($childrens); diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index 674da95b09..479adc67c8 100755 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -2957,7 +2957,7 @@ function reporting_group_report($report, $content) if (empty($id_group)) { $events = []; } else { - $sql_where = sprintf(' AND id_grupo IN (%s) AND estado<>1 ', implode(',', $id_group)); + $sql_where = sprintf(' WHERE id_grupo IN (%s) AND estado<>1 ', implode(',', $id_group)); $events = events_get_events_grouped( $sql_where, 0, @@ -2972,7 +2972,11 @@ function reporting_group_report($report, $content) $return['data']['count_events'] = count($events); - $return['data']['group_stats'] = reporting_get_group_stats($content['id_group']); + $return['data']['group_stats'] = reporting_get_group_stats( + $content['id_group'], + 'AR', + (bool) $content['recursion'] + ); if ($config['metaconsole']) { metaconsole_restore_db(); @@ -3912,7 +3916,7 @@ function reporting_alert_report_group($report, $content) $agent_modules = alerts_get_agent_modules( $content['id_group'], - $content['recursion'] + (((string) $content['id_group'] === '0') ? true : $content['recursion']) ); if (empty($alerts)) { @@ -9066,7 +9070,7 @@ function reporting_get_agents_detailed_event( * * @return array Group statistics */ -function reporting_get_group_stats($id_group=0, $access='AR') +function reporting_get_group_stats($id_group=0, $access='AR', $recursion=true) { global $config; @@ -9168,16 +9172,19 @@ function reporting_get_group_stats($id_group=0, $access='AR') // Store the groups where we are quering $covered_groups = []; $group_array = []; - foreach ($id_group as $group) { - $children = groups_get_childrens($group); - // Show empty groups only if they have children with agents - // $group_array = array(); - foreach ($children as $sub) { - // If the group is quering previously, we ingore it - if (!in_array($sub['id_grupo'], $covered_groups)) { - array_push($covered_groups, $sub['id_grupo']); - array_push($group_array, $sub['id_grupo']); + foreach ($id_group as $group) { + if ($recursion === true) { + $children = groups_get_children($group); + + // Show empty groups only if they have children with agents + // $group_array = array(); + foreach ($children as $sub) { + // If the group is quering previously, we ingore it + if (!in_array($sub['id_grupo'], $covered_groups)) { + array_push($covered_groups, $sub['id_grupo']); + array_push($group_array, $sub['id_grupo']); + } } } diff --git a/pandora_console/include/functions_tags.php b/pandora_console/include/functions_tags.php index 5aace86006..fe36bc34fa 100644 --- a/pandora_console/include/functions_tags.php +++ b/pandora_console/include/functions_tags.php @@ -941,7 +941,7 @@ function tags_get_acl_tags_event_condition( } // Group condition (The module belongs to an agent of the group X) - // $group_condition = sprintf('id_grupo IN (%s)', implode(',', array_values(groups_get_id_recursive($group_id, true))));. + // $group_condition = sprintf('id_grupo IN (%s)', implode(',', array_values(groups_get_children_ids($group_id, true))));. $group_condition = '('.$id_grupo_table_pretag.'id_grupo = '.$group_id.' OR '.$alt_id_grupo_table_pretag.'id_group = '.$group_id.')'; // Tags condition (The module has at least one of the restricted tags). @@ -1350,7 +1350,7 @@ function tags_checks_event_acl($id_user, $id_group, $access, $tags=[], $children foreach ($user_tags as $user_tag) { $tags_user = $user_tag['tags']; $id_group_user = $user_tag['id_grupo']; - $childrens = groups_get_childrens($id_group_user, null, true); + $childrens = groups_get_children($id_group_user, null, true); if (empty($childrens)) { $group_ids = $id_group_user; @@ -1421,7 +1421,7 @@ function tags_get_agents_counter($id_tag, $groups_and_tags=[], $agent_filter=[], $tags_arr = explode(',', $tags); foreach ($tags_arr as $tag) { if ($tag == $id_tag) { - $hierarchy_groups = groups_get_id_recursive($group_id); + $hierarchy_groups = groups_get_children_ids($group_id); $groups_id = array_merge($groups_id, $hierarchy_groups); } } @@ -1923,7 +1923,7 @@ function tags_get_monitors_counter($id_tag, $groups_and_tags=[], $agent_filter=[ $tags_arr = explode(',', $tags); foreach ($tags_arr as $tag) { if ($tag == $id_tag) { - $hierarchy_groups = groups_get_id_recursive($group_id); + $hierarchy_groups = groups_get_children_ids($group_id); $groups_id = array_merge($groups_id, $hierarchy_groups); } } @@ -2219,7 +2219,7 @@ function tags_monitors_fired_alerts($id_tag, $groups_and_tags=[], $id_agente=fal $tags_arr = explode(',', $tags); foreach ($tags_arr as $tag) { if ($tag == $id_tag) { - $hierarchy_groups = groups_get_id_recursive($group_id); + $hierarchy_groups = groups_get_children_ids($group_id); $groups_id = array_merge($groups_id, $hierarchy_groups); } } @@ -2283,7 +2283,7 @@ function tags_get_monitors_alerts($id_tag, $groups_and_tags=[], $id_agente=false $tags_arr = explode(',', $tags); foreach ($tags_arr as $tag) { if ($tag == $id_tag) { - $hierarchy_groups = groups_get_id_recursive($group_id); + $hierarchy_groups = groups_get_children_ids($group_id); $groups_id = array_merge($groups_id, $hierarchy_groups); } } diff --git a/pandora_console/include/functions_treeview.php b/pandora_console/include/functions_treeview.php index 25e0f67020..67bed22be3 100755 --- a/pandora_console/include/functions_treeview.php +++ b/pandora_console/include/functions_treeview.php @@ -802,7 +802,7 @@ function treeview_printTable($id_agente, $server_data=[], $no_head=false) $events_graph = '<div style="width: 100%; height: 90px; display: flex; flex-direction: row; justify-content: center;">'; $events_graph .= graph_graphic_agentevents( $id_agente, - '385px;', + '340px;margin:0', 45, SECONDS_1DAY, '', diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index ab6079fb36..65e6facc93 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -2762,6 +2762,7 @@ function get_shape_status_set($type) // Small squares. case STATUS_SERVER_OK: case STATUS_SERVER_DOWN: + case STATUS_SERVER_CRASH: $return = ['class' => 'status_small_squares']; break; @@ -2773,6 +2774,9 @@ function get_shape_status_set($type) case STATUS_AGENT_OK_BALL: case STATUS_AGENT_NO_DATA_BALL: case STATUS_AGENT_NO_MONITORS_BALL: + case STATUS_SERVER_OK_BALL: + case STATUS_SERVER_DOWN_BALL: + case STATUS_SERVER_CRASH_BALL: $return = ['class' => 'status_balls']; break; diff --git a/pandora_console/include/functions_update_manager.php b/pandora_console/include/functions_update_manager.php index 2b3dcbc093..6156e5e174 100755 --- a/pandora_console/include/functions_update_manager.php +++ b/pandora_console/include/functions_update_manager.php @@ -73,6 +73,24 @@ function update_manager_verify_trial() } +/** + * Check if the trial license is not expired. + * + * @return boolean true if the trial license is expired, false otherwise. + */ +function update_manager_verify_license_expired() +{ + global $config; + + $current_date = date('Ymd'); + if (isset($config['license_expiry_date']) && $current_date >= $config['license_expiry_date']) { + return true; + } + + return false; +} + + /** * Parses responses from configuration wizard. * @@ -454,13 +472,20 @@ function registration_wiz_process() function registration_wiz_modal( $return=false, $launch=true, - $callback=false + $callback=false, + $return_message=false ) { global $config; $output = ''; // Do not show the wizard for trial licenses. if (update_manager_verify_trial()) { + ui_print_info_message('Your license is trial. Please contact Artica at info@artica.es for a valid license', '', $return_message); + return ''; + } + + if (update_manager_verify_license_expired()) { + ui_print_error_message('The license has expired. Please contact Artica at info@artica.es', '', $return_message); return ''; } diff --git a/pandora_console/include/graphs/flot/jquery.flot.exportdata.pandora.js b/pandora_console/include/graphs/flot/jquery.flot.exportdata.pandora.js index 6466a72835..47b8879ace 100644 --- a/pandora_console/include/graphs/flot/jquery.flot.exportdata.pandora.js +++ b/pandora_console/include/graphs/flot/jquery.flot.exportdata.pandora.js @@ -1,425 +1,424 @@ -(function ($) { - var options = { - export: { - export_data: false, // or true - labels_long: null, - homeurl: "", - }, - }; +(function($) { + var options = { + export: { + export_data: false, // or true + labels_long: null, + homeurl: "" + } + }; - function init(plot) { - plot.exportDataCSV = function (args) { - //amount = plot.getOptions().export.type, - //options = options || {}; + function init(plot) { + plot.exportDataCSV = function(args) { + //amount = plot.getOptions().export.type, + //options = options || {}; - // Options - var type = "csv"; - type = type.toLowerCase().trim(); + // Options + var type = "csv"; + type = type.toLowerCase().trim(); - var graphData, - dataObject, - dataObjects = plot.getData(), - result = []; + var graphData, + dataObject, + dataObjects = plot.getData(), + result = []; - // Throw errors - var retrieveDataOject = function (dataObjects) { - var result; + // Throw errors + var retrieveDataOject = function(dataObjects) { + var result; - if (typeof dataObjects === "undefined") - throw new Error("Empty parameter"); + if (typeof dataObjects === "undefined") + throw new Error("Empty parameter"); - // Try to retrieve the avg set (not 100% reliable, I know) - if (dataObjects.length == 1) { - result = dataObjects.shift(); - } - if (dataObjects.length > 1) { - dataObjects.forEach(function (element) { - if (/^Avg.:/i.test(element.label)) result = element; - }); + // Try to retrieve the avg set (not 100% reliable, I know) + if (dataObjects.length == 1) { + result = dataObjects.shift(); + } + if (dataObjects.length > 1) { + dataObjects.forEach(function(element) { + if (/^Avg.:/i.test(element.label)) result = element; + }); - // If the avg set is missing, retrieve the first set - if (typeof result === "undefined") result = dataObjects.shift(); - } + // If the avg set is missing, retrieve the first set + if (typeof result === "undefined") result = dataObjects.shift(); + } - if (typeof result === "undefined") throw new Error("Empty result"); + if (typeof result === "undefined") throw new Error("Empty result"); - return result; - }; + return result; + }; - // Throw errors - var processDataObject = function (dataObject) { - var result; + // Throw errors + var processDataObject = function(dataObject) { + var result; - if (typeof dataObject === "undefined") - throw new Error("Empty parameter"); + if (typeof dataObject === "undefined") + throw new Error("Empty parameter"); - if ( - typeof dataObject.data === "undefined" || - !(dataObject.data instanceof Array) - ) - throw new Error("Object malformed"); + if ( + typeof dataObject.data === "undefined" || + !(dataObject.data instanceof Array) + ) + throw new Error("Object malformed"); - /* { - * head: [<column>,<column>,...,<column>], - * data: [ - * [<data>,<data>,...,<data>], - * [<data>,<data>,...,<data>], - * ..., - * [<data>,<data>,...,<data>], - * ] - * } - */ - if (type === "csv") { - result = { - head: ["timestap", "date", "value", "label"], - data: [], - }; + /* { + * head: [<column>,<column>,...,<column>], + * data: [ + * [<data>,<data>,...,<data>], + * [<data>,<data>,...,<data>], + * ..., + * [<data>,<data>,...,<data>], + * ] + * } + */ + if (type === "csv") { + result = { + head: ["timestamp", "date", "value", "label"], + data: [] + }; - dataObject.data.forEach(function (item, index) { - var timestap = item[0]; + dataObject.data.forEach(function(item, index) { + var timestamp = item[0]; - var d = new Date(item[0]); - var monthNames = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; + var d = new Date(item[0]); + var monthNames = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ]; - date_format = - (d.getDate() < 10 ? "0" : "") + - d.getDate() + - " " + - monthNames[d.getMonth()] + - " " + - d.getFullYear() + - " " + - (d.getHours() < 10 ? "0" : "") + - d.getHours() + - ":" + - (d.getMinutes() < 10 ? "0" : "") + - d.getMinutes() + - ":" + - (d.getSeconds() < 10 ? "0" : "") + - d.getSeconds(); + date_format = + (d.getDate() < 10 ? "0" : "") + + d.getDate() + + " " + + monthNames[d.getMonth()] + + " " + + d.getFullYear() + + " " + + (d.getHours() < 10 ? "0" : "") + + d.getHours() + + ":" + + (d.getMinutes() < 10 ? "0" : "") + + d.getMinutes() + + ":" + + (d.getSeconds() < 10 ? "0" : "") + + d.getSeconds(); - var date = date_format; + var date = date_format; - var value = item[1]; + var value = item[1]; - var clean_label = plot.getOptions().export.labels_long[ - dataObject.label - ]; - clean_label = clean_label.replace(new RegExp(" ", "g"), " "); - result.data.push([timestap, date, value, clean_label]); - }); - } else if (type === "json") { - /* [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ], - * [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ], - * ..., - * [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ] - */ - result = []; + var clean_label = plot.getOptions().export.labels_long[ + dataObject.label + ]; + clean_label = clean_label.replace(new RegExp(" ", "g"), " "); + result.data.push([timestamp, date, value, clean_label]); + }); + } else if (type === "json") { + /* [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ], + * [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ], + * ..., + * [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ] + */ + result = []; - dataObject.data.forEach(function (item, index) { - var date = "", - value = item[1]; + dataObject.data.forEach(function(item, index) { + var date = "", + value = item[1]; - // Long labels are preferred - if (typeof labels_long[index] !== "undefined") - date = labels_long[index]; - else if (typeof labels[index] !== "undefined") date = labels[index]; + // Long labels are preferred + if (typeof labels_long[index] !== "undefined") + date = labels_long[index]; + else if (typeof labels[index] !== "undefined") date = labels[index]; - result.push({ - date: date, - value: value, - label: dataObject.label, - }); - }); - } + result.push({ + date: date, + value: value, + label: dataObject.label + }); + }); + } - if (typeof result === "undefined") throw new Error("Empty result"); + if (typeof result === "undefined") throw new Error("Empty result"); - return result; - }; + return result; + }; - try { - var elements = []; - dataObject = retrieveDataOject(dataObjects); - if (dataObject) { - elements.push(processDataObject(dataObject)); - } - dataObjects.forEach(function (element) { - elements.push(processDataObject(element)); - }); - graphData = elements; + try { + var elements = []; + dataObject = retrieveDataOject(dataObjects); + if (dataObject) { + elements.push(processDataObject(dataObject)); + } + dataObjects.forEach(function(element) { + elements.push(processDataObject(element)); + }); + graphData = elements; + // Transform the object data into a string + // cause PHP has limitations in the number + // of POST params received. + var graphDataStr = JSON.stringify(graphData); - // Transform the object data into a string - // cause PHP has limitations in the number - // of POST params received. - var graphDataStr = JSON.stringify(graphData); + // Build form + var $form = $("<form></form>"), + $dataInput = $("<input>"), + $typeInput = $("<input>"), + $separatorInput = $("<input>"), + $excelInput = $("<input>"); - // Build form - var $form = $("<form></form>"), - $dataInput = $("<input>"), - $typeInput = $("<input>"), - $separatorInput = $("<input>"), - $excelInput = $("<input>"); + $dataInput + .prop("name", "data") + .prop("type", "text") + .prop("value", graphDataStr); - $dataInput - .prop("name", "data") - .prop("type", "text") - .prop("value", graphDataStr); + $typeInput + .prop("name", "type") + .prop("type", "text") + .prop("value", type); - $typeInput - .prop("name", "type") - .prop("type", "text") - .prop("value", type); + $separatorInput + .prop("name", "separator") + .prop("type", "text") + .prop("value", ";"); - $separatorInput - .prop("name", "separator") - .prop("type", "text") - .prop("value", ";"); + $excelInput + .prop("name", "excel_encoding") + .prop("type", "text") + .prop("value", 0); - $excelInput - .prop("name", "excel_encoding") - .prop("type", "text") - .prop("value", 0); + $form + .prop("method", "POST") + .prop( + "action", + plot.getOptions().export.homeurl + "include/graphs/export_data.php" + ) + .append($dataInput, $typeInput, $separatorInput, $excelInput) + .hide() + // Firefox made me write into the DOM for this :( + .appendTo("body") + .submit(); + } catch (e) { + alert("There was an error exporting the data"); + } + }; - $form - .prop("method", "POST") - .prop( - "action", - plot.getOptions().export.homeurl + "include/graphs/export_data.php" - ) - .append($dataInput, $typeInput, $separatorInput, $excelInput) - .hide() - // Firefox made me write into the DOM for this :( - .appendTo("body") - .submit(); - } catch (e) { - alert("There was an error exporting the data"); - } - }; + plot.exportDataJSON = function(args) { + //amount = plot.getOptions().export.type, + //options = options || {}; - plot.exportDataJSON = function (args) { - //amount = plot.getOptions().export.type, - //options = options || {}; + // Options + var type = "json"; + type = type.toLowerCase().trim(); - // Options - var type = "json"; - type = type.toLowerCase().trim(); + var graphData, + dataObject, + dataObjects = plot.getData(), + result = []; - var graphData, - dataObject, - dataObjects = plot.getData(), - result = []; + // Throw errors + var retrieveDataOject = function(dataObjects) { + var result; - // Throw errors - var retrieveDataOject = function (dataObjects) { - var result; + if (typeof dataObjects === "undefined") + throw new Error("Empty parameter"); - if (typeof dataObjects === "undefined") - throw new Error("Empty parameter"); + // Try to retrieve the avg set (not 100% reliable, I know) + if (dataObjects.length == 1) { + result = dataObjects.shift(); + } + if (dataObjects.length > 1) { + dataObjects.forEach(function(element) { + if (/^Avg.:/i.test(element.label)) result = element; + }); - // Try to retrieve the avg set (not 100% reliable, I know) - if (dataObjects.length == 1) { - result = dataObjects.shift(); - } - if (dataObjects.length > 1) { - dataObjects.forEach(function (element) { - if (/^Avg.:/i.test(element.label)) result = element; - }); + // If the avg set is missing, retrieve the first set + if (typeof result === "undefined") result = dataObjects.shift(); + } - // If the avg set is missing, retrieve the first set - if (typeof result === "undefined") result = dataObjects.shift(); - } + if (typeof result === "undefined") throw new Error("Empty result"); - if (typeof result === "undefined") throw new Error("Empty result"); + return result; + }; - return result; - }; + // Throw errors + var processDataObject = function(dataObject) { + var result; - // Throw errors - var processDataObject = function (dataObject) { - var result; + if (typeof dataObject === "undefined") + throw new Error("Empty parameter"); - if (typeof dataObject === "undefined") - throw new Error("Empty parameter"); + if ( + typeof dataObject.data === "undefined" || + !(dataObject.data instanceof Array) + ) + throw new Error("Object malformed"); - if ( - typeof dataObject.data === "undefined" || - !(dataObject.data instanceof Array) - ) - throw new Error("Object malformed"); + /* { + * head: [<column>,<column>,...,<column>], + * data: [ + * [<data>,<data>,...,<data>], + * [<data>,<data>,...,<data>], + * ..., + * [<data>,<data>,...,<data>], + * ] + * } + */ + if (type === "csv") { + result = { + head: ["date", "value", "label"], + data: [] + }; - /* { - * head: [<column>,<column>,...,<column>], - * data: [ - * [<data>,<data>,...,<data>], - * [<data>,<data>,...,<data>], - * ..., - * [<data>,<data>,...,<data>], - * ] - * } - */ - if (type === "csv") { - result = { - head: ["date", "value", "label"], - data: [], - }; + dataObject.data.forEach(function(item, index) { + var date = "", + value = item[1]; - dataObject.data.forEach(function (item, index) { - var date = "", - value = item[1]; + // Long labels are preferred + if ( + typeof plot.getOptions().export.labels_long[index] !== "undefined" + ) + date = plot.getOptions().export.labels_long[index]; + else if (typeof labels[index] !== "undefined") date = labels[index]; - // Long labels are preferred - if ( - typeof plot.getOptions().export.labels_long[index] !== "undefined" - ) - date = plot.getOptions().export.labels_long[index]; - else if (typeof labels[index] !== "undefined") date = labels[index]; + result.data.push([date, value, dataObject.label]); + }); + } else if (type === "json") { + /* [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ], + * [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ], + * ..., + * [ + * { + * 'date': <date>, + * 'value': <value> + * } + * ] + */ + result = []; - result.data.push([date, value, dataObject.label]); - }); - } else if (type === "json") { - /* [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ], - * [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ], - * ..., - * [ - * { - * 'date': <date>, - * 'value': <value> - * } - * ] - */ - result = []; + dataObject.data.forEach(function(item, index) { + var date = "", + value = item[1]; - dataObject.data.forEach(function (item, index) { - var date = "", - value = item[1]; + // Long labels are preferred + if (typeof labels_long[index] !== "undefined") + date = labels_long[index]; + else if (typeof labels[index] !== "undefined") date = labels[index]; - // Long labels are preferred - if (typeof labels_long[index] !== "undefined") - date = labels_long[index]; - else if (typeof labels[index] !== "undefined") date = labels[index]; + result.push({ + date: date, + value: value, + label: dataObject.label + }); + }); + } - result.push({ - date: date, - value: value, - label: dataObject.label, - }); - }); - } + if (typeof result === "undefined") throw new Error("Empty result"); - if (typeof result === "undefined") throw new Error("Empty result"); + return result; + }; - return result; - }; + try { + var elements = []; + var custom_graph = $("input:hidden[name=custom_graph]").value; - try { - var elements = []; - var custom_graph = $("input:hidden[name=custom_graph]").value; + if (custom_graph) { + dataObject = retrieveDataOject(dataObjects); + dataObjects.forEach(function(element) { + elements.push(processDataObject(element)); + }); + graphData = elements; + } else { + dataObject = retrieveDataOject(dataObjects); + elements.push(processDataObject(dataObject)); + graphData = elements; + } - if (custom_graph) { - dataObject = retrieveDataOject(dataObjects); - dataObjects.forEach(function (element) { - elements.push(processDataObject(element)); - }); - graphData = elements; - } else { - dataObject = retrieveDataOject(dataObjects); - elements.push(processDataObject(dataObject)); - graphData = elements; - } + // Transform the object data into a string + // cause PHP has limitations in the number + // of POST params received. + var graphDataStr = JSON.stringify(graphData); - // Transform the object data into a string - // cause PHP has limitations in the number - // of POST params received. - var graphDataStr = JSON.stringify(graphData); + // Build form + var $form = $("<form></form>"), + $dataInput = $("<input>"), + $typeInput = $("<input>"), + $separatorInput = $("<input>"), + $excelInput = $("<input>"); - // Build form - var $form = $("<form></form>"), - $dataInput = $("<input>"), - $typeInput = $("<input>"), - $separatorInput = $("<input>"), - $excelInput = $("<input>"); + $dataInput + .prop("name", "data") + .prop("type", "text") + .prop("value", graphDataStr); - $dataInput - .prop("name", "data") - .prop("type", "text") - .prop("value", graphDataStr); + $typeInput + .prop("name", "type") + .prop("type", "text") + .prop("value", type); - $typeInput - .prop("name", "type") - .prop("type", "text") - .prop("value", type); + $separatorInput + .prop("name", "separator") + .prop("type", "text") + .prop("value", ";"); - $separatorInput - .prop("name", "separator") - .prop("type", "text") - .prop("value", ";"); + $excelInput + .prop("name", "excel_encoding") + .prop("type", "text") + .prop("value", 0); - $excelInput - .prop("name", "excel_encoding") - .prop("type", "text") - .prop("value", 0); + $form + .prop("method", "POST") + .prop( + "action", + plot.getOptions().export.homeurl + "include/graphs/export_data.php" + ) + .append($dataInput, $typeInput, $separatorInput, $excelInput) + .hide() + // Firefox made me write into the DOM for this :( + .appendTo("body") + .submit(); + } catch (e) { + alert("There was an error exporting the data"); + } + }; + } - $form - .prop("method", "POST") - .prop( - "action", - plot.getOptions().export.homeurl + "include/graphs/export_data.php" - ) - .append($dataInput, $typeInput, $separatorInput, $excelInput) - .hide() - // Firefox made me write into the DOM for this :( - .appendTo("body") - .submit(); - } catch (e) { - alert("There was an error exporting the data"); - } - }; - } - - $.plot.plugins.push({ - init: init, - options: options, - name: "exportdata", - version: "0.1", - }); + $.plot.plugins.push({ + init: init, + options: options, + name: "exportdata", + version: "0.1" + }); })(jQuery); diff --git a/pandora_console/include/graphs/flot/pandora.flot.js b/pandora_console/include/graphs/flot/pandora.flot.js index 87ecf4b33f..a35b5dd71b 100644 --- a/pandora_console/include/graphs/flot/pandora.flot.js +++ b/pandora_console/include/graphs/flot/pandora.flot.js @@ -230,21 +230,6 @@ function pandoraFlotPieCustom( ); } var legends = $("#" + graph_id + " .legendLabel"); - var j = 0; - legends.each(function() { - //$(this).css("width", $(this).width()); - $(this).css("font-size", font_size + "pt"); - $(this).removeClass("legendLabel"); - $(this).addClass(font); - $(this).text(legend[j]); - j++; - }); - - if ($('input[name="custom_graph"]').val()) { - $(".legend>div").css("right", $(".legend>div").height() * -1); - $(".legend>table").css("right", $(".legend>div").height() * -1); - } - //$('.legend>table').css('border',"1px solid #E2E2E2"); if (background_color == "transparent") { $(".legend>table").css("background-color", ""); diff --git a/pandora_console/include/graphs/functions_flot.php b/pandora_console/include/graphs/functions_flot.php index dc4e556292..81c9cc79cf 100644 --- a/pandora_console/include/graphs/functions_flot.php +++ b/pandora_console/include/graphs/functions_flot.php @@ -346,13 +346,7 @@ function menu_graph( $threshold = true; } - $return .= "<div id='general_menu_$graph_id' class='menu_graph' style=' - width: 20px; - height: 150px; - left:100%; - position: absolute; - top: 0px; - background-color: tranparent;'>"; + $return .= "<div id='general_menu_$graph_id' class='menu_graph'>"; $return .= "<div id='menu_$graph_id' "."style='display: none; ".'text-align: center;'.'position: relative;'."border-bottom: 0px;'> <a href='javascript:'><img id='menu_cancelzoom_$graph_id' src='".$params['homeurl']."images/zoom_cross_grey.disabled.png' alt='".__('Cancel zoom')."' title='".__('Cancel zoom')."'></a>"; if ($threshold) { @@ -745,13 +739,12 @@ function flot_slicesbar_graph( // Set some containers to legend, graph, timestamp tooltip, etc. $height = ((int) $height + 15); - if ($stat_win) { - $return = "<div id='$graph_id' class='noresizevc graph $adapt_key' style='width: ".$width.'%; height: '.$height."px; display: inline-block;'></div>"; - } else { - $return = "<div id='$graph_id' class='noresizevc graph $adapt_key' style='width: ".$width.'%; height: '.$height."px;'></div>"; - } - $return .= "<div id='value_$graph_id' style='display:none; position:absolute; background:#fff; border: solid 1px #aaa; padding: 2px'></div>"; + $style = 'width:'.$width.'%;'; + $style .= 'height:'.$height.'px;'; + $return = "<div id='".$graph_id."' class='noresizevc graph ".$adapt_key."' style='".$style."'></div>"; + + $return .= "<div id='value_".$graph_id."' style='display:none; position:absolute; background:#fff; border: solid 1px #aaa; padding: 2px'></div>"; // Set a weird separator to serialize and unserialize // passing data from php to javascript. diff --git a/pandora_console/include/javascript/connection_check.js b/pandora_console/include/javascript/connection_check.js new file mode 100644 index 0000000000..5ea72d2184 --- /dev/null +++ b/pandora_console/include/javascript/connection_check.js @@ -0,0 +1,170 @@ +/** + * ------------------------------------- + * Connection Check + * -------------------------------------- + */ + +checkConnection(1); + +/** + * Performs connection tests every minutes and add connection listeners + * @param {integer} time in minutes + */ + +function checkConnection(minutes) { + var cicle = minutes * 60 * 1000; + var checkConnection = setInterval(handleConnection, cicle); + + // Connection listeters. + window.addEventListener("online", handleConnection); + window.addEventListener("offline", handleConnection); +} + +/** + * Handle connection status test. + * + * Test conectivity with server and shows modal message. + */ +function handleConnection() { + var connected; + var msg = "online"; + + if (navigator.onLine) { + isReachable(getServerUrl()) + .then(function(online) { + if (online) { + // handle online status + connected = true; + showConnectionMessage(connected, msg); + } else { + connected = false; + msg = "No connectivity with server"; + showConnectionMessage(connected, msg); + } + }) + .catch(function(err) { + connected = false; + msg = err; + showConnectionMessage(connected, msg); + }); + } else { + // handle offline status + connected = false; + msg = "Connection offline"; + showConnectionMessage(connected, msg); + } +} + +/** + * Test server reachibilty and get response. + * + * @param {String} url + * + * Return {promise} + */ +function isReachable(url) { + /** + * Note: fetch() still "succeeds" for 404s on subdirectories, + * which is ok when only testing for domain reachability. + * + * Example: + * https://google.com/noexist does not throw + * https://noexist.com/noexist does throw + */ + return fetch(url, { method: "HEAD", mode: "no-cors" }) + .then(function(resp) { + return resp && (resp.ok || resp.type === "opaque"); + }) + .catch(function(error) { + console.warn("[conn test failure]:", error); + }); +} + +/** + * Gets server origin url + */ +function getServerUrl() { + var server_url; + + server_url = window.location.origin; + + return server_url; +} + +/** + * Shows or hide connection infoMessage. + * + * @param {bool} conn + * @param {string} msg + */ +function showConnectionMessage(conn = true, msg = "") { + var data = {}; + if (conn) { + $("div#message_dialog_connection") + .closest(".ui-dialog-content") + .dialog("close"); + } else { + data.title = "Connection with server has been lost"; + data.text = "Connection status: " + msg; + + infoMessage(data, "message_dialog_connection"); + } +} + +function infoMessage(data, idMsg) { + var title = data.title; + var err_messge = data.text; + + if (idMsg == null) { + idMsg = uniqId(); + } + + if ($("#" + idMsg).length === 0) { + $("body").append('<div title="' + title + '" id="' + idMsg + '"></div>'); + $("#" + idMsg).empty(); + } + + $("#err_msg").empty(); + $("#err_msg").html("\n\n" + err_messge); + + $("#" + idMsg) + .dialog({ + height: 250, + width: 528, + opacity: 1, + modal: true, + position: { + my: "center", + at: "center", + of: window, + collision: "fit" + }, + title: data.title, + buttons: [ + { + class: + "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", + text: "Retry", + click: function(e) { + handleConnection(); + } + }, + { + class: + "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-cancel", + text: "Close", + click: function() { + $(this).dialog("close"); + } + } + ], + + open: function(event, ui) { + $(".ui-widget-overlay").addClass("error-modal-opened"); + }, + close: function(event, ui) { + $(".ui-widget-overlay").removeClass("error-modal-opened"); + } + }) + .show(); +} diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index f99ae01c79..04a8f5336e 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -786,13 +786,12 @@ function post_process_select_events_unit(name, selected) { function post_process_select_events(name) { $("." + name + "_toggler").click(function() { var value = $("#text-" + name + "_text").val(); - var count = $("#" + name + "_select option").filter(function(i, item) { if (Number($(item).val()) == Number(value)) return true; else return false; }).length; - if (count != 1) { + if (count < 1) { $("#" + name + "_select").append( $("<option>") .val(value) @@ -1931,120 +1930,3 @@ function ajaxRequest(id, settings) { } }); } - -/** - * ------------------------------------- - * Connection Check - * -------------------------------------- - */ - -checkConnection(1); - -/** - * Performs connection tests every minutes and add connection listeners - * @param {integer} time in minutes - */ - -function checkConnection(minutes) { - var cicle = minutes * 60 * 1000; - var checkConnection = setInterval(handleConnection, cicle); - - // Connection listeters. - window.addEventListener("online", handleConnection); - window.addEventListener("offline", handleConnection); -} - -/** - * Handle connection status test. - * - * Test conectivity with server and shows modal message. - */ -function handleConnection() { - var connected; - var msg = "online"; - - if (navigator.onLine) { - isReachable(getServerUrl()) - .then(function(online) { - if (online) { - // handle online status - connected = true; - showConnectionMessage(connected, msg); - } else { - connected = false; - msg = "No connectivity with server"; - showConnectionMessage(connected, msg); - } - }) - .catch(function(err) { - connected = false; - msg = err; - showConnectionMessage(connected, msg); - }); - } else { - // handle offline status - connected = false; - msg = "Connection offline"; - showConnectionMessage(connected, msg); - } -} - -/** - * Test server reachibilty and get response. - * - * @param {String} url - * - * Return {promise} - */ -function isReachable(url) { - /** - * Note: fetch() still "succeeds" for 404s on subdirectories, - * which is ok when only testing for domain reachability. - * - * Example: - * https://google.com/noexist does not throw - * https://noexist.com/noexist does throw - */ - return fetch(url, { method: "HEAD", mode: "no-cors" }) - .then(function(resp) { - return resp && (resp.ok || resp.type === "opaque"); - }) - .catch(function(error) { - console.warn("[conn test failure]:", error); - }); -} - -/** - * Gets server origin url - */ -function getServerUrl() { - var server_url; - - try { - server_url = get_php_value("homeurl"); - } catch (SyntaxError) { - console.warn("Pandora homeurl cannot be found."); - server_url = $("#hidden-homeurl").val(); - } - return server_url; -} - -/** - * Shows or hide connection infoMessage. - * - * @param {bool} conn - * @param {string} msg - */ -function showConnectionMessage(conn = true, msg = "") { - var data = {}; - if (conn) { - $("div#message_dialog_connection") - .closest(".ui-dialog-content") - .dialog("close"); - } else { - data.title = "Connection with server has been lost"; - data.text = "Connection status: " + msg; - - infoMessage(data, "message_dialog_connection"); - } -} diff --git a/pandora_console/include/javascript/pandora_events.js b/pandora_console/include/javascript/pandora_events.js index 55c8ecb74a..c1b604b4e2 100644 --- a/pandora_console/include/javascript/pandora_events.js +++ b/pandora_console/include/javascript/pandora_events.js @@ -453,7 +453,6 @@ function perform_response_massive(response, response_id, out_iterator) { // Change the status of an event to new, in process or validated. function event_change_status(event_ids) { var new_status = $("#estado").val(); - var event_id = $("#hidden-id_event").val(); var meta = $("#hidden-meta").val(); var history = $("#hidden-history").val(); @@ -472,7 +471,7 @@ function event_change_status(event_ids) { type: "POST", url: $("#hidden-ajax_file").val(), async: true, - dataType: "html", + dataType: "json", success: function(data) { $("#button-status_button").removeAttr("disabled"); $("#response_loading").hide(); @@ -485,11 +484,20 @@ function event_change_status(event_ids) { $("#notification_status_error").hide(); } - if (data == "status_ok") { + if (data.status == "status_ok") { if (typeof dt_events !== "undefined") { dt_events.draw(false); } $("#notification_status_success").show(); + if (new_status == 1) { + $("#extended_event_general_page table td.general_acknowleded").text( + data.user + ); + } else { + $("#extended_event_general_page table td.general_acknowleded").text( + "N/A" + ); + } } else { $("#notification_status_error").show(); } @@ -942,7 +950,6 @@ function execute_event_response(event_list_btn) { }); break; case "delete_selected": - console.log($(this)); $(".chk_val:checked").each(function() { execute_delete_event_reponse( dt_events, diff --git a/pandora_console/include/javascript/pandora_ui.js b/pandora_console/include/javascript/pandora_ui.js index 2445473591..15b7f83217 100644 --- a/pandora_console/include/javascript/pandora_ui.js +++ b/pandora_console/include/javascript/pandora_ui.js @@ -494,61 +494,3 @@ function generalShowMsg(data, idMsg) { ] }); } - -function infoMessage(data, idMsg) { - var title = data.title; - var err_messge = data.text; - - if (idMsg == null) { - idMsg = uniqId(); - } - - if ($("#" + idMsg).length === 0) { - $("body").append('<div title="' + title + '" id="' + idMsg + '"></div>'); - $("#" + idMsg).empty(); - } - - $("#err_msg").empty(); - $("#err_msg").html("\n\n" + err_messge); - - $("#" + idMsg) - .dialog({ - height: 250, - width: 528, - opacity: 1, - modal: true, - position: { - my: "center", - at: "center", - of: window, - collision: "fit" - }, - title: data.title, - buttons: [ - { - class: - "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", - text: "Retry", - click: function(e) { - handleConnection(); - } - }, - { - class: - "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-cancel", - text: "Close", - click: function() { - $(this).dialog("close"); - } - } - ], - - open: function(event, ui) { - $(".ui-widget-overlay").addClass("error-modal-opened"); - }, - close: function(event, ui) { - $(".ui-widget-overlay").removeClass("error-modal-opened"); - } - }) - .show(); -} diff --git a/pandora_console/include/javascript/tree/TreeController.js b/pandora_console/include/javascript/tree/TreeController.js index 497e18c266..1aeb7ad799 100644 --- a/pandora_console/include/javascript/tree/TreeController.js +++ b/pandora_console/include/javascript/tree/TreeController.js @@ -12,6 +12,8 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. +/*global $, _*/ + var TreeController = { controllers: [], getController: function() { @@ -38,12 +40,35 @@ var TreeController = { return; } + function _recursiveGroupsCount(elements, childGroupsLength) { + if (typeof childGroupsLength === "undefined") { + childGroupsLength = 0; + } + + _.each(elements, function(element) { + if (typeof element.children !== "undefined") { + childGroupsLength = _recursiveGroupsCount( + element.children, + childGroupsLength + ); + childGroupsLength += element.children.length; + } + }); + return childGroupsLength; + } + // Load branch function _processGroup(container, elements, rootGroup) { var $group = $("<ul></ul>"); + var childGroupsLength = _recursiveGroupsCount(elements); - // First group + // First group. if (typeof rootGroup != "undefined" && rootGroup == true) { + var messageLength = controller.tree.length; + if (childGroupsLength > 0) { + messageLength = childGroupsLength + controller.tree.length; + } + $group .addClass("tree-root") .hide() @@ -54,13 +79,12 @@ var TreeController = { 'images/pandora.png" />' + "<span class='margin-left-1'>" + (controller.tree.length > 0 - ? controller.foundMessage + ": " + controller.tree.length + ? controller.foundMessage + ": " + messageLength : "") + "</div>" ); - } - // Normal group - else { + } else { + // Normal group. $group.addClass("tree-group").hide(); } diff --git a/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_group.php b/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_group.php index 2acd7f32fa..bd7d7d5886 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_group.php +++ b/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_group.php @@ -278,6 +278,11 @@ class TopNEventByGroupWidget extends Widget ]; // Groups. + $selected_groups = []; + if ($values['groupId']) { + $selected_groups = explode(',', $values['groupId'][0]); + } + $inputs[] = [ 'label' => __('Groups'), 'arguments' => [ @@ -285,7 +290,7 @@ class TopNEventByGroupWidget extends Widget 'name' => 'groupId[]', 'returnAllGroup' => true, 'privilege' => 'AR', - 'selected' => explode(',', $values['groupId'][0]), + 'selected' => $selected_groups, 'return' => true, 'multiple' => true, ], diff --git a/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_module.php b/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_module.php index 4bbaee22a8..148ace6aac 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_module.php +++ b/pandora_console/include/lib/Dashboard/Widgets/top_n_events_by_module.php @@ -277,6 +277,11 @@ class TopNEventByModuleWidget extends Widget ], ]; + $selected_groups = []; + if ($values['groupId']) { + $selected_groups = explode(',', $values['groupId'][0]); + } + // Groups. $inputs[] = [ 'label' => __('Groups'), @@ -285,7 +290,7 @@ class TopNEventByModuleWidget extends Widget 'name' => 'groupId[]', 'returnAllGroup' => true, 'privilege' => 'AR', - 'selected' => explode(',', $values['groupId'][0]), + 'selected' => $selected_groups, 'return' => true, 'multiple' => true, ], diff --git a/pandora_console/include/load_session.php b/pandora_console/include/load_session.php index 3575310141..b557edd5d3 100644 --- a/pandora_console/include/load_session.php +++ b/pandora_console/include/load_session.php @@ -64,14 +64,23 @@ function pandora_session_close() function pandora_session_read($session_id) { $session_id = addslashes($session_id); - $session_data = db_get_value( - 'data', - 'tsessions_php', - 'id_session', - $session_id + + // Do not use SQL cache here. + $session_data = db_get_all_rows_sql( + sprintf( + 'SELECT data + FROM `tsessions_php` WHERE id_session="%s"', + $session_id + ), + false, + false ); - if (!empty($session_data)) { + if (is_array($session_data) === true) { + $session_data = $session_data[0]['data']; + } + + if (empty($session_data) === false) { return $session_data; } else { return ''; @@ -90,7 +99,6 @@ function pandora_session_read($session_id) function pandora_session_write($session_id, $data) { $session_id = addslashes($session_id); - if (is_ajax()) { // Avoid session upadte while processing ajax responses - notifications. if (get_parameter('check_new_notifications', false)) { @@ -101,18 +109,22 @@ function pandora_session_write($session_id, $data) $values = []; $values['last_active'] = time(); - if (!empty($data)) { + if (empty($data) === false) { $values['data'] = addslashes($data); } - $session_exists = (bool) db_get_value( - 'COUNT(id_session)', - 'tsessions_php', - 'id_session', - $session_id + // Do not use SQL cache here. + $session_exists = db_get_all_rows_sql( + sprintf( + 'SELECT id_session + FROM `tsessions_php` WHERE id_session="%s"', + $session_id + ), + false, + false ); - if (!$session_exists) { + if ($session_exists === false) { $values['id_session'] = $session_id; $retval_write = db_process_sql_insert('tsessions_php', $values); } else { @@ -198,11 +210,69 @@ function pandora_session_gc($max_lifetime=300) } -$result_handler = session_set_save_handler( - 'pandora_session_open', - 'pandora_session_close', - 'pandora_session_read', - 'pandora_session_write', - 'pandora_session_destroy', - 'pandora_session_gc' -); +/** + * Enables custom session handlers. + * + * @return boolean Context changed or not. + */ +function enable_session_handlers() +{ + global $config; + + if ($config['_using_pandora_sessionhandlers'] !== true) { + if (session_status() !== PHP_SESSION_NONE) { + // Close previous version. + session_write_close(); + } + + $sesion_handler = session_set_save_handler( + 'pandora_session_open', + 'pandora_session_close', + 'pandora_session_read', + 'pandora_session_write', + 'pandora_session_destroy', + 'pandora_session_gc' + ); + + session_start(); + + // Restore previous session. + $config['_using_pandora_sessionhandlers'] = true; + return $sesion_handler; + } + + return false; +} + + +/** + * Disables custom session handlers. + * + * @param string|null $id_session Force swap to target session. + * + * @return void + */ +function disable_session_handlers($id_session=null) +{ + global $config; + + if (session_status() !== PHP_SESSION_NONE) { + // Close previous version. + session_write_close(); + } + + $ss = new SessionHandler(); + session_set_save_handler($ss, true); + + if ($id_session !== null) { + session_id($id_session); + } + + session_start(); + + $config['_using_pandora_sessionhandlers'] = false; +} + + +// Always enable session handler. +$result_handler = enable_session_handlers(); diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index 2507cfdb30..656e5b2f7b 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -462,6 +462,10 @@ select:-internal-list-box { width: 120px; max-width: 120px; } +.w200px { + width: 200px; + max-width: 200px; +} .w240px { width: 240px; max-width: 240px; @@ -3094,6 +3098,12 @@ div#stat-win-module-graph div.nodata_container { } .menu_graph { + width: 30px; + height: 150px; + left: 100%; + position: absolute; + top: 0px; + background-color: transparent; -moz-border-top-right-radius: 6px; -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; @@ -5893,7 +5903,7 @@ table.table_modal_alternate tr td:first-child { } .flot-text { - width: 101%; + width: 100%; } /*Font header feedback*/ diff --git a/pandora_console/index.php b/pandora_console/index.php index af8671ded7..1d72a5a5af 100755 --- a/pandora_console/index.php +++ b/pandora_console/index.php @@ -222,7 +222,7 @@ echo '<head>'."\n"; ob_start('ui_process_page_head'); // Enterprise main. -enterprise_include('index.php'); +enterprise_include_once('index.php'); echo '<script type="text/javascript">'; echo 'var dispositivo = navigator.userAgent.toLowerCase();'; @@ -273,6 +273,7 @@ if (strlen($search) > 0) { } // Login process. +enterprise_include_once('include/auth/saml.php'); if (! isset($config['id_user'])) { // Clear error messages. unset($_COOKIE['errormsg']); @@ -395,24 +396,33 @@ if (! isset($config['id_user'])) { $nick_in_db = $_SESSION['prepared_login_da']['id_user']; $expired_pass = false; } else if (($config['auth'] == 'saml') && ($login_button_saml)) { - $saml_configured = include_once $config['homedir'].'/'.ENTERPRISE_DIR.'/include/auth/saml.php'; - - if (!$saml_configured) { - include_once 'general/noaccesssaml.php'; - } - - $saml_user_id = saml_process_user_login(); - + $saml_user_id = enterprise_hook('saml_process_user_login'); if (!$saml_user_id) { - include_once 'general/noaccesssaml.php'; - } + $login_failed = true; + include_once 'general/login_page.php'; + while (@ob_end_flush()) { + // Dumping... + continue; + } + exit('</html>'); + } $nick_in_db = $saml_user_id; if (!$nick_in_db) { - include_once $config['saml_path'].'simplesamlphp/lib/_autoload.php'; - $as = new SimpleSAML_Auth_Simple($config['saml_source']); - $as->logout(); + if ($config['auth'] === 'saml') { + enterprise_hook('saml_logout'); + } + + if (session_status() !== PHP_SESSION_NONE) { + $_SESSION = []; + session_destroy(); + header_remove('Set-Cookie'); + setcookie(session_name(), $_COOKIE[session_name()], (time() - 4800), '/'); + } + + // Process logout. + include 'general/logoff.php'; } } else { // process_user_login is a virtual function which should be defined in each auth file. @@ -735,7 +745,7 @@ if (! isset($config['id_user'])) { exit('</html>'); } - } else { + } else if (isset($_GET['bye']) === false) { // There is no user connected. if ($config['enterprise_installed']) { enterprise_include_once('include/functions_reset_pass.php'); @@ -750,7 +760,17 @@ if (! isset($config['id_user'])) { $pass2 = get_parameter_post('pass2'); $id_user = get_parameter_post('id_user'); - if ($correct_pass_change && !empty($pass1) && !empty($pass2) && !empty($id_user)) { + if ($reset_hash != '') { + $hash_data = explode(':::', $reset_hash); + $id_user = $hash_data[0]; + $codified_hash = $hash_data[1]; + + $db_reset_pass_entry = db_get_value_filter('reset_time', 'treset_pass', ['id_user' => $id_user, 'cod_hash' => $id_user.':::'.$codified_hash]); + } + + if ($correct_pass_change && !empty($pass1) && !empty($pass2) && !empty($id_user) && $db_reset_pass_entry) { + delete_reset_pass_entry($id_user); + $correct_reset_pass_process = ''; $process_error_message = ''; @@ -787,21 +807,14 @@ if (! isset($config['id_user'])) { include_once 'general/login_page.php'; } else { if ($reset_hash != '') { - $hash_data = explode(':::', $reset_hash); - $id_user = $hash_data[0]; - $codified_hash = $hash_data[1]; - - $db_reset_pass_entry = db_get_value_filter('reset_time', 'treset_pass', ['id_user' => $id_user, 'cod_hash' => $id_user.':::'.$codified_hash]); $process_error_message = ''; if ($db_reset_pass_entry) { if (($db_reset_pass_entry + SECONDS_2HOUR) < time()) { register_pass_change_try($id_user, 0); $process_error_message = __('Too much time since password change request'); - delete_reset_pass_entry($id_user); include_once 'general/login_page.php'; } else { - delete_reset_pass_entry($id_user); include_once 'enterprise/include/process_reset_pass.php'; } } else { @@ -950,6 +963,10 @@ if (! isset($config['id_user'])) { } exit('</html>'); + } else { + if ($config['auth'] === 'saml') { + enterprise_hook('saml_login_status_verifier'); + } } } } @@ -961,19 +978,19 @@ if (file_exists(ENTERPRISE_DIR.'/load_enterprise.php')) { // Log off. if (isset($_GET['bye'])) { - include 'general/logoff.php'; $iduser = $_SESSION['id_usuario']; + if ($config['auth'] === 'saml') { + enterprise_hook('saml_logout'); + } + $_SESSION = []; session_destroy(); header_remove('Set-Cookie'); setcookie(session_name(), $_COOKIE[session_name()], (time() - 4800), '/'); - if ($config['auth'] == 'saml') { - include_once $config['saml_path'].'simplesamlphp/lib/_autoload.php'; - $as = new SimpleSAML_Auth_Simple('PandoraFMS'); - $as->logout(); - } + // Process logout. + include 'general/logoff.php'; while (@ob_end_flush()) { // Dumping... @@ -1252,8 +1269,8 @@ echo '</div>'; echo '<div id="um_msg_receiver">'; echo '</div>'; - // Connection lost alert. +ui_require_javascript_file('connection_check'); $conn_title = __('Connection with server has been lost'); $conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); diff --git a/pandora_console/install.php b/pandora_console/install.php index f706f1dff4..9283f6b267 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -129,7 +129,7 @@ <div style='height: 10px'> <?php $version = '7.0NG.750'; - $build = '201029'; + $build = '201123'; $banner = "v$version Build $build"; error_reporting(0); diff --git a/pandora_console/mobile/operation/events.php b/pandora_console/mobile/operation/events.php index cca5d7d18e..41d078e1eb 100644 --- a/pandora_console/mobile/operation/events.php +++ b/pandora_console/mobile/operation/events.php @@ -731,7 +731,7 @@ class Events $system = System::getInstance(); // --------------Fill the SQL POST------------------------------- - $sql_post = ''; + $sql_post = ' WHERE 1=1 '; switch ($this->status) { case 0: diff --git a/pandora_console/operation/agentes/estado_agente.php b/pandora_console/operation/agentes/estado_agente.php index c0e6d147c5..9e01425198 100644 --- a/pandora_console/operation/agentes/estado_agente.php +++ b/pandora_console/operation/agentes/estado_agente.php @@ -546,7 +546,7 @@ if (!empty($search_custom)) { if ($group_id > 0) { $groups = [$group_id]; if ($recursion) { - $groups = groups_get_id_recursive($group_id, true); + $groups = groups_get_children_ids($group_id, true); } } else { $groups = []; @@ -576,7 +576,7 @@ if ($strict_user) { if ($group_id > 0) { $groups = [$group_id]; if ($recursion) { - $groups = groups_get_id_recursive($group_id, true); + $groups = groups_get_children_ids($group_id, true); } $filter['id_group'] = implode(',', $groups); @@ -902,7 +902,6 @@ if (!empty($table->data)) { if (check_acl($config['id_user'], 0, 'AW') || check_acl($config['id_user'], 0, 'AM')) { echo '<div style="text-align: right; float: right;">'; echo '<form method="post" action="index.php?sec=gagente&sec2=godmode/agentes/configurar_agente">'; - html_print_input_hidden('new_agent', 1); html_print_submit_button(__('Create agent'), 'crt', false, 'class="sub next"'); echo '</form>'; echo '</div>'; @@ -913,7 +912,6 @@ if (!empty($table->data)) { ui_print_info_message([ 'no_close' => true, 'message' => __('There are no defined agents') ]); echo '<div style="text-align: right; float: right;">'; echo '<form method="post" action="index.php?sec=gagente&sec2=godmode/agentes/configurar_agente">'; - html_print_input_hidden('new_agent', 1); html_print_submit_button(__('Create agent'), 'crt', false, 'class="sub next"'); echo '</form>'; echo '</div>'; diff --git a/pandora_console/operation/agentes/pandora_networkmap.editor.php b/pandora_console/operation/agentes/pandora_networkmap.editor.php index a16874705c..8699253454 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.editor.php +++ b/pandora_console/operation/agentes/pandora_networkmap.editor.php @@ -313,7 +313,7 @@ if ($not_found) { $table->data[6][1] = html_print_input_text('scale_z', $scale_z, '', 2, 10, true).ui_print_help_tip(__('Introduce zoom level. 1 = Highest resolution. Figures may include decimals'), true); $table->data['source'][0] = __('Source'); - $table->data['source'][1] = html_print_radio_button('source', 'group', __('Group'), $source, true, $disabled_source).html_print_radio_button('source', 'recon_task', __('Recon task'), $source, true, $disabled_source).html_print_radio_button('source', 'ip_mask', __('CIDR IP mask'), $source, true, $disabled_source); + $table->data['source'][1] = html_print_radio_button('source', 'group', __('Group'), $source, true, $disabled_source).html_print_radio_button('source', 'recon_task', __('Discovery task'), $source, true, $disabled_source).html_print_radio_button('source', 'ip_mask', __('CIDR IP mask'), $source, true, $disabled_source); $table->data['source_data_recon_task'][0] = __('Source from recon task'); $table->data['source_data_recon_task'][0] .= ui_print_help_tip( diff --git a/pandora_console/operation/agentes/stat_win.php b/pandora_console/operation/agentes/stat_win.php index 1d26666b57..a75e30e269 100644 --- a/pandora_console/operation/agentes/stat_win.php +++ b/pandora_console/operation/agentes/stat_win.php @@ -35,6 +35,7 @@ require_once $config['homedir'].'/include/functions_graph.php'; require_once $config['homedir'].'/include/functions_modules.php'; require_once $config['homedir'].'/include/functions_agents.php'; require_once $config['homedir'].'/include/functions_tags.php'; +require_once $config['homedir'].'/include/php_to_js_values.php'; enterprise_include_once('include/functions_agents.php'); check_login(); @@ -85,6 +86,7 @@ ui_require_css_file('register', 'include/styles/', true); // Connection lost alert. $conn_title = __('Connection with server has been lost'); $conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); +ui_require_javascript_file('connection_check'); ui_print_message_dialog( $conn_title, $conn_text, diff --git a/pandora_console/operation/agentes/status_monitor.php b/pandora_console/operation/agentes/status_monitor.php index a49db7b7f4..db1e052ab9 100644 --- a/pandora_console/operation/agentes/status_monitor.php +++ b/pandora_console/operation/agentes/status_monitor.php @@ -1,6 +1,5 @@ <?php - - +// This file is an example on how things must NEVER be done. // Pandora FMS - http://pandorafms.com // ================================================== // Copyright (c) 2005-2010 Artica Soluciones Tecnologicas @@ -41,7 +40,7 @@ if (! defined('METACONSOLE')) { $buttons['fields'] = [ 'active' => false, - 'text' => '<a href="index.php?sec=view&sec2=operation/agentes/status_monitor&section=fields">'.html_print_image('images/custom_columns.png', true, ['title' => __('Custom fields')]).'</a>', + 'text' => '<a href="index.php?sec=view&sec2=operation/agentes/status_monitor§ion=fields">'.html_print_image('images/custom_columns.png', true, ['title' => __('Custom fields')]).'</a>', 'operation' => true, ]; @@ -79,22 +78,27 @@ if (! defined('METACONSOLE')) { ui_meta_print_header(__('Monitor view')); } -$ag_freestring = (string) get_parameter('ag_freestring'); -$moduletype = (string) get_parameter('moduletype'); -$datatype = (string) get_parameter('datatype'); -$ag_modulename = (string) get_parameter('ag_modulename'); -$refr = (int) get_parameter('refr', 0); -$offset = (int) get_parameter('offset', 0); -$status = (int) get_parameter('status', 4); -$modulegroup = (int) get_parameter('modulegroup', -1); -$tag_filter = (int) get_parameter('tag_filter', 0); -$min_hours_status = (string) get_parameter('min_hours_status', ''); -// Sort functionality -$sortField = get_parameter('sort_field'); -$sort = get_parameter('sort', 'none'); -// When the previous page was a visualmap and show only one module -$id_module = (int) get_parameter('id_module', 0); -$ag_custom_fields = (array) get_parameter('ag_custom_fields', []); +$recursion = get_parameter_switch('recursion', false); +if ($recursion === false) { + $recursion = get_parameter('recursion', false); +} + +$ag_freestring = (string) get_parameter('ag_freestring'); +$moduletype = (string) get_parameter('moduletype'); +$datatype = (string) get_parameter('datatype'); +$ag_modulename = (string) get_parameter('ag_modulename'); +$refr = (int) get_parameter('refr', 0); +$offset = (int) get_parameter('offset', 0); +$status = (int) get_parameter('status', 4); +$modulegroup = (int) get_parameter('modulegroup', -1); +$tag_filter = (int) get_parameter('tag_filter', 0); +$min_hours_status = (string) get_parameter('min_hours_status', ''); +// Sort functionality. +$sortField = get_parameter('sort_field'); +$sort = get_parameter('sort', 'none'); +// When the previous page was a visualmap and show only one module. +$id_module = (int) get_parameter('id_module', 0); +$ag_custom_fields = (array) get_parameter('ag_custom_fields', []); $module_option = (int) get_parameter('module_option', 1); $autosearch = false; @@ -161,11 +165,22 @@ if (is_numeric($ag_group)) { // Agent group selector if (!is_metaconsole()) { if ($ag_group > 0 && check_acl($config['id_user'], $ag_group, 'AR')) { - $sql_conditions_group = sprintf( - ' AND (tagente.id_grupo = %d OR tasg.id_group = %d)', - $ag_group, - $ag_group - ); + if ($recursion) { + $all_groups = groups_get_children_ids($ag_group, true); + + // User has explicit permission on group 1 ? + $sql_conditions_group = sprintf( + ' AND (tagente.id_grupo IN (%s) OR tasg.id_group IN (%s)) ', + implode(',', $all_groups), + implode(',', $all_groups) + ); + } else { + $sql_conditions_group = sprintf( + ' AND (tagente.id_grupo = %d OR tasg.id_group = %d)', + $ag_group, + $ag_group + ); + } } else if ($user_groups != '') { // User has explicit permission on group 1 ? $sql_conditions_group = ' AND ( @@ -175,11 +190,22 @@ if (!is_metaconsole()) { } } else { if (((int) $ag_group !== 0) && (check_acl($config['id_user'], $id_ag_group, 'AR'))) { - $sql_conditions_group = sprintf( - ' AND (tagente.id_grupo IN (%s) OR tasg.id_group IN (%s))', - $ag_group, - $ag_group - ); + if ($recursion) { + $all_groups = groups_get_children_ids($ag_group, true); + + // User has explicit permission on group 1 ? + $sql_conditions_group = sprintf( + ' AND (tagente.id_grupo IN (%s) OR tasg.id_group IN (%s)) ', + implode(',', $all_groups), + implode(',', $all_groups) + ); + } else { + $sql_conditions_group = sprintf( + ' AND (tagente.id_grupo IN (%s) OR tasg.id_group IN (%s))', + $ag_group, + $ag_group + ); + } } else if ($user_groups != '') { // User has explicit permission on group 1 ? $sql_conditions_group = ' AND ( @@ -355,7 +381,8 @@ $table->style[3] = 'font-weight: bold;'; $table->style[4] = 'font-weight: bold;'; $table->data[0][0] = __('Group'); -$table->data[0][1] = html_print_select_groups( +$table->data[0][1] = '<div class="flex flex-row-vcenter w290px"><div class="w200px">'; +$table->data[0][1] .= html_print_select_groups( $config['id_user'], 'AR', true, @@ -375,6 +402,18 @@ $table->data[0][1] = html_print_select_groups( 'id_grupo', false ); +$table->data[0][1] .= '</div><div>'; +$table->data[0][1] .= html_print_input( + [ + 'type' => 'checkbox', + 'name' => 'recursion', + 'return' => true, + 'checked' => $recursion, + 'value' => 1, + ] +); +$table->data[0][1] .= __('Recursion'); +$table->data[0][1] .= '</div></div>'; $fields = []; $fields[AGENT_MODULE_STATUS_NORMAL] = __('Normal'); @@ -701,8 +740,7 @@ foreach ($custom_fields as $custom_field) { $table_custom_fields->data[] = $row; } - -$filters = '<form method="post" action="index.php?sec=view&sec2=operation/agentes/status_monitor&refr='.$refr.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&module_option='.$module_option.'&ag_modulename='.$ag_modulename.'&moduletype='.$moduletype.'&datatype='.$datatype.'&status='.$status.'&sort_field='.$sortField.'&sort='.$sort.'&pure='.$config['pure'].$ag_custom_fields_params.'">'; +$filters = '<form method="post" action="index.php?sec=view&sec2=operation/agentes/status_monitor&refr='.$refr.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&module_option='.$module_option.'&ag_modulename='.$ag_modulename.'&moduletype='.$moduletype.'&datatype='.$datatype.'&status='.$status.'&sort_field='.$sortField.'&sort='.$sort.'&pure='.$config['pure'].$ag_custom_fields_params.'">'; if (is_metaconsole()) { $table->colspan[4][0] = 7; $table->cellstyle[4][0] = 'padding: 10px;'; @@ -970,7 +1008,7 @@ switch ($sortField) { } $sql = 'SELECT - (SELECT GROUP_CONCAT(ttag.name SEPARATOR \',\') + (SELECT GROUP_CONCAT(ttag.name SEPARATOR \',\') FROM ttag WHERE ttag.id_tag IN ( SELECT ttag_module.id_tag @@ -1014,6 +1052,7 @@ $sql = 'SELECT ORDER BY '.$order['field'].' '.$order['order'].' LIMIT '.$offset.','.$limit_sql; + // We do not show the modules until the user searches with the filter if ($autosearch) { if (! defined('METACONSOLE')) { @@ -1102,17 +1141,51 @@ if (($config['dbtype'] == 'oracle') && ($result !== false)) { // Urls to sort the table. -$url_agent_name = 'index.php?sec=view&sec2=operation/agentes/status_monitor&refr='.$refr.'&datatype='.$datatype.'&moduletype='.$moduletype.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=agent_alias&sort='; -$url_type = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=type&sort='; -$url_module_name = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=module_name&sort='; -$url_server_type = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=moduletype&sort='; -$url_interval = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=interval&sort='; -$url_status = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=status&sort='; -$url_status = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=last_status_change&sort='; -$url_data = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=data&sort='; -$url_timestamp_up = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=timestamp&sort=up'; -$url_timestamp_down = 'index.php?sec=view&sec2=operation/agentes/status_monitor&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params.'&sort_field=timestamp&sort=down'; +$url_agent_name = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_type = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_module_name = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_server_type = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_interval = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_status = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_status = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_data = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_timestamp_up = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_timestamp_down = 'index.php?sec=view&sec2=operation/agentes/status_monitor'; +$url_agent_name .= '&refr='.$refr.'&datatype='.$datatype.'&moduletype='.$moduletype.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_type .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_module_name .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_server_type .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_interval .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_status .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_status .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_data .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_timestamp_up .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; +$url_timestamp_down .= '&datatype='.$datatype.'&moduletype='.$moduletype.'&refr='.$refr.'&modulegroup='.$modulegroup.'&offset='.$offset.'&ag_group='.$ag_group.'&ag_freestring='.$ag_freestring.'&ag_modulename='.$ag_modulename.'&status='.$status.$ag_custom_fields_params; + +// Holy god... +$url_agent_name .= '&recursion='.$recursion; +$url_type .= '&recursion='.$recursion; +$url_module_name .= '&recursion='.$recursion; +$url_server_type .= '&recursion='.$recursion; +$url_interval .= '&recursion='.$recursion; +$url_status .= '&recursion='.$recursion; +$url_status .= '&recursion='.$recursion; +$url_data .= '&recursion='.$recursion; +$url_timestamp_up .= '&recursion='.$recursion; +$url_timestamp_down .= '&recursion='.$recursion; + + +$url_agent_name .= '&sort_field=agent_alias&sort='; +$url_type .= '&sort_field=type&sort='; +$url_module_name .= '&sort_field=module_name&sort='; +$url_server_type .= '&sort_field=moduletype&sort='; +$url_interval .= '&sort_field=interval&sort='; +$url_status .= '&sort_field=status&sort='; +$url_status .= '&sort_field=last_status_change&sort='; +$url_data .= '&sort_field=data&sort='; +$url_timestamp_up .= '&sort_field=timestamp&sort=up'; +$url_timestamp_down .= '&sort_field=timestamp&sort=down'; // Start Build List Result if (!empty($result)) { @@ -1276,9 +1349,9 @@ if (!empty($result)) { } if (is_metaconsole()) { - $data[0] = '<a href="?sec=gmodules&sec2=advanced/policymanager&id='.$policyInfo['id_policy'].'">'.html_print_image($img, true, ['title' => $title]).'</a>'; + $data[0] = '<a href="?sec=gmodules&sec2=advanced/policymanager&id='.$policyInfo['id_policy'].'">'.html_print_image($img, true, ['title' => $title]).'</a>'; } else { - $data[0] = '<a href="?sec=gmodules&sec2=enterprise/godmode/policies/policies&id='.$policyInfo['id_policy'].'">'.html_print_image($img, true, ['title' => $title]).'</a>'; + $data[0] = '<a href="?sec=gmodules&sec2=enterprise/godmode/policies/policies&id='.$policyInfo['id_policy'].'">'.html_print_image($img, true, ['title' => $title]).'</a>'; } } @@ -1293,7 +1366,7 @@ if (!empty($result)) { // TODO: Calculate hash access before to use it more simply like other sections. I.E. Events view if (defined('METACONSOLE')) { - $agent_link = '<a href="'.$row['server_url'].'index.php?'.'sec=estado&'.'sec2=operation/agentes/ver_agente&'.'id_agente='.$row['id_agent'].'&'.'loginhash=auto&'.'loginhash_data='.$row['hashdata'].'&'.'loginhash_user='.str_rot13($row['user']).'">'; + $agent_link = '<a href="'.$row['server_url'].'index.php?'.'sec=estado&'.'sec2=operation/agentes/ver_agente&'.'id_agente='.$row['id_agent'].'&'.'loginhash=auto&'.'loginhash_data='.$row['hashdata'].'&'.'loginhash_user='.str_rot13($row['user']).'">'; $agent_alias = ui_print_truncate_text( $agent_alias, 'agent_small', @@ -1309,7 +1382,7 @@ if (!empty($result)) { $data[1] = $agent_alias; } } else { - $data[1] = '<strong><a href="index.php?sec=estado&sec2=operation/agentes/ver_agente&id_agente='.$row['id_agent'].'">'; + $data[1] = '<strong><a href="index.php?sec=estado&sec2=operation/agentes/ver_agente&id_agente='.$row['id_agent'].'">'; $data[1] .= ui_print_truncate_text($agent_alias, 'agent_medium', false, true, false, '[…]', 'font-size:7.5pt;'); $data[1] .= '</a></strong>'; } @@ -1325,9 +1398,9 @@ if (!empty($result)) { $show_edit_icon = false; } - $url_edit_module = $row['server_url'].'index.php?'.'sec=gagente&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$row['id_agent'].'&'.'tab=module&'.'id_agent_module='.$row['id_agente_modulo'].'&'.'edit_module=1'.'&loginhash=auto&loginhash_data='.$row['hashdata'].'&loginhash_user='.str_rot13($row['user']); + $url_edit_module = $row['server_url'].'index.php?'.'sec=gagente&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$row['id_agent'].'&'.'tab=module&'.'id_agent_module='.$row['id_agente_modulo'].'&'.'edit_module=1'.'&loginhash=auto&loginhash_data='.$row['hashdata'].'&loginhash_user='.str_rot13($row['user']); } else { - $url_edit_module = 'index.php?'.'sec=gagente&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$row['id_agent'].'&'.'tab=module&'.'id_agent_module='.$row['id_agente_modulo'].'&'.'edit_module=1'; + $url_edit_module = 'index.php?'.'sec=gagente&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$row['id_agent'].'&'.'tab=module&'.'id_agent_module='.$row['id_agente_modulo'].'&'.'edit_module=1'; } if ($show_edit_icon) { @@ -1750,24 +1823,13 @@ if (!empty($result)) { // End Build List Result. echo "<div id='monitor_details_window'></div>"; -// Strict user hidden. -echo '<div id="strict_hidden" style="display:none;">'; -html_print_input_text('strict_user_hidden', $strict_user); -echo '</div>'; enterprise_hook('close_meta_frame'); ui_require_javascript_file('pandora_modules'); ?> -<script type='text/javascript'> -$(document).ready (function () { - if ($('#ag_group').val() != 0) { - $('#tag_filter').css('display', 'none'); - $('#tag_td').css('display', 'none'); - } -}); - +<script type="text/javascript"> $('#moduletype').click(function() { jQuery.get ( @@ -1789,17 +1851,6 @@ $('#moduletype').click(function() { return false; }); -$('#ag_group').change (function () { - strict_user = $('#text-strict_user_hidden').val(); - - if (($('#ag_group').val() != 0) && (strict_user != 0)) { - $('#tag_filter').css('display', 'none'); - $('#tag_td').css('display', 'none'); - } else { - $('#tag_filter').css('display', ''); - $('#tag_td').css('display', ''); - } -}); function toggle_full_value(id) { text = $('#hidden_value_module_' + id).html(); diff --git a/pandora_console/operation/agentes/ver_agente.php b/pandora_console/operation/agentes/ver_agente.php index e86960938a..df5146711c 100644 --- a/pandora_console/operation/agentes/ver_agente.php +++ b/pandora_console/operation/agentes/ver_agente.php @@ -88,7 +88,7 @@ if (is_ajax()) { if ($get_agents_group_json) { $id_group = (int) get_parameter('id_group'); - $recursion = (bool) get_parameter('recursion'); + $recursion = (get_parameter_switch('recursion', 'false') === 'true'); $id_os = get_parameter('id_os', ''); $agent_name = get_parameter('name', ''); @@ -146,14 +146,24 @@ if (is_ajax()) { // Perform search. $agents = agents_get_group_agents( + // Id_group. $id_group, + // Search. $filter, + // Case. 'lower', - false, + // NoACL. + true, + // ChildGroups. $recursion, + // Serialized. false, + // Separator. '|', - $cluster_mode + // Add_alert_bulk_op. + $cluster_mode, + // Force_serialized. + false ); if (empty($agents)) { diff --git a/pandora_console/operation/events/events.build_query.php b/pandora_console/operation/events/events.build_query.php index b1b4051e7f..0f68cbfb5f 100755 --- a/pandora_console/operation/events/events.build_query.php +++ b/pandora_console/operation/events/events.build_query.php @@ -28,7 +28,7 @@ if ($id_group > 0) { if ($propagate) { $childrens_ids = [$id_group]; - $childrens = groups_get_childrens($id_group, null, true); + $childrens = groups_get_children($id_group, null, true); if (!empty($childrens)) { foreach ($childrens as $child) { diff --git a/pandora_console/operation/events/events.php b/pandora_console/operation/events/events.php index 3ca4123b4f..f24aa98699 100644 --- a/pandora_console/operation/events/events.php +++ b/pandora_console/operation/events/events.php @@ -358,6 +358,21 @@ if (is_ajax()) { $tmp->comments = ui_print_comments($tmp->comments); } + // Show last event. + if (isset($tmp->max_id_evento) && $tmp->max_id_evento !== $tmp->id_evento) { + $max_event = db_get_row_sql( + sprintf( + 'SELECT criticity, timestamp FROM %s + WHERE id_evento = %s', + ($tmp->meta) ? 'tmetaconsole_event' : 'tevento', + $tmp->max_id_evento + ) + ); + + $tmp->timestamp = $max_event['timestamp']; + $tmp->criticity = $max_event['criticity']; + } + $tmp->agent_name = io_safe_output($tmp->agent_name); $tmp->ack_utimestamp = ui_print_timestamp( $tmp->ack_utimestamp, @@ -429,7 +444,7 @@ $user_filter = db_get_row_sql( ) ); -// Do not load the user filter if we come from the 24h event graph +// Do not load the user filter if we come from the 24h event graph. $from_event_graph = get_parameter('filter[from_event_graph]', $filter['from_event_graph']); if ($user_filter !== false && $from_event_graph != 1) { $filter = events_get_event_filter($user_filter['id_filter']); @@ -442,6 +457,13 @@ if ($user_filter !== false && $from_event_graph != 1) { $text_agent = $filter['text_agent']; $id_agent = $filter['id_agent']; $id_agent_module = $filter['id_agent_module']; + $text_module = io_safe_output( + db_get_value_filter( + 'nombre', + 'tagente_modulo', + ['id_agente_modulo' => $filter['id_agent_module']] + ) + ); $pagination = $filter['pagination']; $event_view_hr = $filter['event_view_hr']; $id_user_ack = $filter['id_user_ack']; @@ -878,13 +900,17 @@ if (is_metaconsole() !== true) { */ // Group. +if ($id_group_filter === null) { + $id_group_filter = 0; +} + $data = html_print_input( [ 'name' => 'id_group_filter', 'returnAllGroup' => true, 'privilege' => 'AR', 'type' => 'select_groups', - 'selected' => (defined($id_group_filter) ? $id_group_filter : 0), + 'selected' => $id_group_filter, 'nothing' => false, 'return' => true, 'size' => '80%', @@ -1935,16 +1961,21 @@ function process_datatables_item(item) { /* Status */ img = '<?php echo html_print_image('images/star.png', true, ['title' => __('Unknown'), 'class' => 'forced-title']); ?>'; + state = '0'; switch (item.estado) { case "<?php echo EVENT_STATUS_NEW; ?>": img = '<?php echo html_print_image('images/star.png', true, ['title' => __('New event'), 'class' => 'forced-title']); ?>'; break; case "<?php echo EVENT_STATUS_VALIDATED; ?>": + + state = '1'; img = '<?php echo html_print_image('images/tick.png', true, [ 'title' => __('Event validated'), 'class' => 'forced-title']); ?>'; break; case "<?php echo EVENT_STATUS_INPROCESS; ?>": + state = '2'; + img = '<?php echo html_print_image('images/hourglass.png', true, [ 'title' => __('Event in process'), 'class' => 'forced-title']); ?>'; break; } @@ -1976,6 +2007,9 @@ function process_datatables_item(item) { } item.estado = '<div>'; + item.estado += '<span style="display: none">'; + item.estado += state; + item.estado += '</span>'; item.estado += img; item.estado += '</div>'; @@ -1996,6 +2030,9 @@ function process_datatables_item(item) { /* Group name */ if (item.id_grupo == "0") { + var severity_value = "<?php echo $severity; ?>"; + const multiple = severity_value.split(","); + $("#severity").val(multiple); item.id_grupo = "<?php echo __('All'); ?>"; } else { item.id_grupo = item.group_name; @@ -2320,9 +2357,8 @@ $(document).ready( function() { url: '<?php echo ui_get_full_url('ajax.php'); ?>', data: { page: 'include/ajax/events', - load_filter_modal: 1, - current_filter: $('#latest_filter_id').val() - }, + load_filter_modal: 1 + }, success: function (data){ $('#load-modal-filter') .empty() diff --git a/pandora_console/operation/events/events_list.php b/pandora_console/operation/events/events_list.php index ae39dabf3b..b1eed5556c 100644 --- a/pandora_console/operation/events/events_list.php +++ b/pandora_console/operation/events/events_list.php @@ -311,7 +311,7 @@ if ($user_filter != 0 && empty($id_name) && !$update_from_filter_table) { } // Build the condition of the events query. -$sql_post = ''; +$sql_post = ' WHERE 1=1 '; $id_user = $config['id_user']; @@ -1214,7 +1214,7 @@ if ($group_rep == 0) { $sql = 'SELECT COUNT(DISTINCT id_evento) FROM $event_table te $event_lj - WHERE 1=1 $sql_post'; + $sql_post'; $total_events = (int) db_get_sql($sql); } else if ($group_rep == 1) { $total_events = events_get_events_grouped( @@ -1477,7 +1477,8 @@ $(document).ready( function() { $("#text-id_extra").val(val); if (i == 'user_comment') $("#text-user_comment").val(val); - + if (i == 'module_search') + $("#text-module_search").val(val); if(i == 'id_source_event') $("#text-id_source_event").val(val); } diff --git a/pandora_console/operation/events/sound_events.php b/pandora_console/operation/events/sound_events.php index 4377faaa63..7434c18eaf 100644 --- a/pandora_console/operation/events/sound_events.php +++ b/pandora_console/operation/events/sound_events.php @@ -61,6 +61,13 @@ echo '</head>'; echo "<body style='background-color: #494949; max-width: 550px; max-height: 400px; margin-top:40px;'>"; echo "<h1 class='modalheaderh1'>".__('Sound console').'</h1>'; +// Connection lost alert. +ui_require_css_file('register', 'include/styles/', true); +$conn_title = __('Connection with server has been lost'); +$conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); +ui_require_javascript_file('connection_check'); +ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); + $table = new StdClass; $table->width = '100%'; $table->styleTable = 'padding-left:16px; padding-right:16px; padding-top:16px;'; @@ -77,7 +84,7 @@ $table->data[0][2] = __('Type'); $table->data[0][3] = html_print_checkbox('alert_fired', 'alert_fired', true, true, false, 'changeType();').__('Alert fired').'<br />'.html_print_checkbox('critical', 'critical', true, true, false, 'changeType();').__('Monitor critical').'<br />'.html_print_checkbox('unknown', 'unknown', true, true, false, 'changeType();').__('Monitor unknown').'<br />'.html_print_checkbox('warning', 'warning', true, true, false, 'changeType();').__('Monitor warning').'<br />'; $table->data[1][0] = __('Agent'); -$table->data[1][1] = html_print_select($agents, 'id_agents[]', true, false, '', '', true, true, '', '', '', 'width:120px; height:100px', '', false, '', '', true); +$table->data[1][1] = html_print_select($agents, 'id_agents[]', true, false, '', '', true, true, '', '', '', 'max-width:200px; height:100px', '', false, '', '', true); $table->data[1][2] = __('Event'); $table->data[1][3] = html_print_textarea('events_fired', 200, 20, '', 'readonly="readonly" style="max-height:100px; background: #ddd; resize:none;"', true); @@ -152,10 +159,26 @@ function changeGroup() { } function changeType() { - alert_fired = $("input[name=alert_fired]").attr('checked'); - critical = $("input[name=critical]").attr('checked'); - warning = $("input[name=warning]").attr('checked'); - unknown = $("input[name=unknown]").attr('checked'); + alert_fired = false; + critical = false; + warning = false; + unknown = false; + + if($("input[name=alert_fired]").is(':checked') ) { + alert_fired = true; + } + + if($("input[name=critical]").is(':checked') ) { + critical = true; + } + + if($("input[name=warning]").is(':checked') ) { + warning = true; + } + + if($("input[name=unknown]").is(':checked') ) { + unknown = true; + } } function toggleButton() { @@ -256,9 +279,6 @@ $(document).ready (function () { setInterval("check_event()", (10 * 1000)); //10 seconds between ajax request $("#table1").css("background-color", "#fff"); $("#table2").css("background-color", "#fff"); - - group_width = $("#group").width(); - $("#id_agents").width(group_width + 9); }); </script> diff --git a/pandora_console/operation/gis_maps/public_console.php b/pandora_console/operation/gis_maps/public_console.php index ba5b99633c..a756d04c0c 100755 --- a/pandora_console/operation/gis_maps/public_console.php +++ b/pandora_console/operation/gis_maps/public_console.php @@ -273,8 +273,10 @@ if ($layers != false) { gis_activate_ajax_refresh($layers, $timestampLastOperation, 1, $idMap); // Connection lost alert. + ui_require_css_file('register', 'include/styles/', true); $conn_title = __('Connection with server has been lost'); $conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); + ui_require_javascript_file('connection_check'); ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); } diff --git a/pandora_console/operation/visual_console/legacy_public_view.php b/pandora_console/operation/visual_console/legacy_public_view.php index 4df0a6db28..609447800e 100644 --- a/pandora_console/operation/visual_console/legacy_public_view.php +++ b/pandora_console/operation/visual_console/legacy_public_view.php @@ -48,6 +48,7 @@ html_print_input_hidden('homeurl', $config['homeurl']); $url_css_modal = ui_get_full_url('include/styles/register.css', false, false, false); echo '<link rel="stylesheet" href="'.$url_css_modal.'" type="text/css" />'; // Connection lost alert. +ui_require_javascript_file('connection_check', 'include/javascript/', true); $conn_title = __('Connection with server has been lost'); $conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); @@ -157,10 +158,6 @@ echo '<div style="display: none;" id="qrcode_container" title="'.__('QR code of echo '<div id="qrcode_container_image"></div>'; echo '</div>'; -// Connection lost alert. -$conn_title = __('Connection with server has been lost'); -$conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); -ui_print_message_alert($conn_title, $conn_text, 'connection', '/images/error_1.png'); ui_require_jquery_file('countdown', 'include/javascript/', true); ui_require_javascript_file('wz_jsgraphics', 'include/javascript/', true); diff --git a/pandora_console/operation/visual_console/public_view.php b/pandora_console/operation/visual_console/public_view.php index 301ec3ca9c..6cc9f817a1 100644 --- a/pandora_console/operation/visual_console/public_view.php +++ b/pandora_console/operation/visual_console/public_view.php @@ -29,11 +29,10 @@ if (file_exists(ENTERPRISE_DIR.'/include/functions_login.php')) { require_once $config['homedir'].'/vendor/autoload.php'; ui_require_css_file('visual_maps'); -ui_require_css_file('register'); - -html_print_input_hidden('homeurl', $config['homeurl']); +ui_require_css_file('register', 'include/styles/', true); // Connection lost alert. +ui_require_javascript_file('connection_check', 'include/javascript/', true); $conn_title = __('Connection with server has been lost'); $conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); @@ -140,10 +139,6 @@ echo '<div style="display: none;" id="qrcode_container" title="'.__('QR code of echo '<div id="qrcode_container_image"></div>'; echo '</div>'; -// Connection lost alert. -$conn_title = __('Connection with server has been lost'); -$conn_text = __('Connection to the server has been lost. Please check your internet connection or contact with administrator.'); -ui_print_message_dialog($conn_title, $conn_text, 'connection', '/images/error_1.png'); // Check groups can access user. $aclUserGroups = []; diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index 37fa8092c2..beae98c702 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.750 -%define release 201029 +%define release 201123 # 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 162aeaef50..243b8ac9e8 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.750 -%define release 201029 +%define release 201123 # 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 de5a3f753c..8ee2af75d9 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.750 -%define release 201029 +%define release 201123 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_console/pandoradb_data.sql b/pandora_console/pandoradb_data.sql index ad20052428..53b1a1027f 100644 --- a/pandora_console/pandoradb_data.sql +++ b/pandora_console/pandoradb_data.sql @@ -113,7 +113,7 @@ INSERT INTO `tconfig` (`token`, `value`) VALUES ('identification_reminder', 1), ('identification_reminder_timestamp', 0), ('current_package_enterprise', 750), -('post_process_custom_values', '{"0.00000038580247":"Seconds to months","0.00000165343915":"Seconds to weeks","0.00001157407407":"Seconds to days","0.01666666666667":"Seconds to minutes","0.00000000093132":"Bytes to Gigabytes","0.00000095367432":"Bytes to Megabytes","0.0009765625":"Bytes to Kilobytes","0.00000001653439":"Timeticks to weeks","0.00000011574074":"Timeticks to days"}'), +('post_process_custom_values', '{"0.00000038580247":"Seconds to months","0.00000165343915":"Seconds to weeks","0.00001157407407":"Seconds to days","0.01666666666667":"Seconds to minutes","0.00000000093132":"Bytes to Gigabytes","0.00000095367432":"Bytes to Megabytes","0.00097656250000":"Bytes to Kilobytes","0.00000001653439":"Timeticks to weeks","0.00000011574074":"Timeticks to days"}'), ('custom_docs_logo', 'default_docs.png'), ('custom_support_logo', 'default_support.png'), ('custom_logo_white_bg_preview', 'pandora_logo_head_white_bg.png'), @@ -2747,4 +2747,4 @@ SELECT @plugin_id := `id` FROM `tplugin` WHERE `name` = @plugin_name; INSERT IGNORE INTO `tnetwork_component` (`id_nc`, `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`, `str_warning`, `min_critical`, `max_critical`, `str_critical`, `min_ff_event`, `custom_string_1`, `custom_string_2`, `custom_string_3`, `custom_integer_1`, `custom_integer_2`, `post_process`, `unit`, `wizard_level`, `macros`, `critical_instructions`, `warning_instructions`, `unknown_instructions`, `critical_inverse`, `warning_inverse`, `id_category`, `tags`, `disabled_types_event`, `module_macros`, `min_ff_event_normal`, `min_ff_event_warning`, `min_ff_event_critical`, `ff_type`, `each_ff`, `dynamic_interval`, `dynamic_max`, `dynamic_min`, `dynamic_next`, `dynamic_two_tailed`, `module_type`, `protocol`, `manufacturer_id`, `execution_type`, `scan_type`, `value`, `value_operations`, `module_enabled`, `name_oid`, `query_class`, `query_key_field`, `scan_filters`, `query_filters`, `enabled`) VALUES (@component_id,@component_name,@component_description,@group_id,1,0,0,0,0,'','','','',0,9,0,'','','',0,0,0,80.00,90.00,'',90.00,0.00,'',0,'','','',0,0,0.000000000000000,'%','nowizard',CONCAT('{\"extra_field_1\":\"Size\",\"extra_field_2\":\"FreeSpace\",\"satellite_execution\":\"/etc/pandora/satellite_plugins/wizard_wmi_module -host "_address_" -namespace "_namespace_wmi_" -user "_user_wmi_" -pass "_pass_wmi_" -wmiClass "_class_wmi_" -fieldsList "_field_wmi_1_,_field_wmi_2_" -queryFilter "DeviceID = '_DeviceID_'" -operation "((_f1_ - _f2_) * 100) / _f1_" -wmicPath /usr/bin/wmic\",\"value_operation\":\"((_Size_ - _FreeSpace_) * 100) / _Size_\",\"server_plugin\":\"',@plugin_id,'\",\"_field2__wmi_field\":\"_namespace_wmi_\",\"_field1__wmi_field\":\"_address_\",\"_field4__wmi_field\":\"_pass_wmi_\",\"_field3__wmi_field\":\"_user_wmi_\",\"_field6__wmi_field\":\"_field_wmi_1_,_field_wmi_2_\",\"_field5__wmi_field\":\"_class_wmi_\",\"_field8__wmi_field\":\"((_f1_ - _f2_) * 100) / _f1_\",\"_field7__wmi_field\":\"DeviceID = '_DeviceID_'\",\"field0_wmi_field\":\"\"}'),'','','',0,0,0,'','{\"going_unknown\":0}','',0,0,0,0,0,0,0,0,0,0,1,'wmi','',2,2,'','',1,'','Win32_LogicalDisk','DeviceID','','{\"scan\":\"DriveType = 3\",\"execution\":\"\",\"field\":\"\",\"key_string\":\"\"}',1); -INSERT IGNORE INTO `tpen` VALUES (171,'dlink','D-Link Systems, Inc.'),(14988,'mikrotik','MikroTik'),(6486,'alcatel','Alcatel-Lucent Enterprise'),(41112,'ubiquiti','Ubiquiti Networks, Inc.'),(207,'telesis','Allied Telesis, Inc.'),(10002,'frogfoot','Frogfoot Networks'),(2,'ibm','IBM'),(4,'unix','Unix'),(63,'apple','Apple Computer, Inc.'),(674,'dell','Dell Inc.'),(111,'oracle','Oracle'),(116,'hitachi','Hitachi, Ltd.'),(173,'netlink','Netlink'),(188,'ascom','Ascom'),(6574,'synology','Synology Inc.'),(3861,'fujitsu','Fujitsu Network Communications, Inc.'),(53526,'dell','Dell ATC'),(52627,'apple','Apple Inc'),(19464,'hitachi','Hitachi Communication Technologies, Ltd.'),(13062,'ascom','Ascom'); \ No newline at end of file +INSERT IGNORE INTO `tpen` VALUES (171,'dlink','D-Link Systems, Inc.'),(14988,'mikrotik','MikroTik'),(6486,'alcatel','Alcatel-Lucent Enterprise'),(41112,'ubiquiti','Ubiquiti Networks, Inc.'),(207,'telesis','Allied Telesis, Inc.'),(10002,'frogfoot','Frogfoot Networks'),(2,'ibm','IBM'),(4,'unix','Unix'),(63,'apple','Apple Computer, Inc.'),(674,'dell','Dell Inc.'),(111,'oracle','Oracle'),(116,'hitachi','Hitachi, Ltd.'),(173,'netlink','Netlink'),(188,'ascom','Ascom'),(6574,'synology','Synology Inc.'),(3861,'fujitsu','Fujitsu Network Communications, Inc.'),(53526,'dell','Dell ATC'),(52627,'apple','Apple Inc'),(19464,'hitachi','Hitachi Communication Technologies, Ltd.'),(13062,'ascom','Ascom'); diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 1afd3bd5bb..f98a259d24 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.750-201029 +Version: 7.0NG.750-201123 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 2aff52280a..28893137b2 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.750-201029" +pandora_version="7.0NG.750-201123" package_cpan=0 package_pandora=1 diff --git a/pandora_server/bin/pandora_server b/pandora_server/bin/pandora_server index 812bf1e57b..d82944f93b 100755 --- a/pandora_server/bin/pandora_server +++ b/pandora_server/bin/pandora_server @@ -771,7 +771,7 @@ sub main() { die("Server thread crashed.") unless (check_server_threads() == 1); db_do ($DBH, - "UPDATE tserver SET status = 0 + "UPDATE tserver SET status = -1 WHERE UNIX_TIMESTAMP(now())-UNIX_TIMESTAMP(keepalive) > 2*server_keepalive" ); diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index 03f3c1e109..f9961df655 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.750"; -my $pandora_build = "201029"; +my $pandora_build = "201123"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash diff --git a/pandora_server/lib/PandoraFMS/NetworkServer.pm b/pandora_server/lib/PandoraFMS/NetworkServer.pm index 0bca799815..3c0446c956 100644 --- a/pandora_server/lib/PandoraFMS/NetworkServer.pm +++ b/pandora_server/lib/PandoraFMS/NetworkServer.pm @@ -498,7 +498,7 @@ sub exec_network_module ($$$$) { $module_data = pandora_ping_latency ($pa_config, $ip_target, $timeout, $retries); if (defined($module_data)) { - $module_result = 0; # Successful + $module_result = 1; # Unsuccessful } } diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 17a8779e7f..6a9bdcc9bd 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.750"; -my $pandora_build = "201029"; +my $pandora_build = "201123"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/lib/PandoraFMS/Tools.pm b/pandora_server/lib/PandoraFMS/Tools.pm index 300e66e5a6..4c9683c888 100755 --- a/pandora_server/lib/PandoraFMS/Tools.pm +++ b/pandora_server/lib/PandoraFMS/Tools.pm @@ -856,6 +856,24 @@ sub clean_blank { return $input; } +################################################################################ +# Erase blank spaces before and after the string +################################################################################ +sub trim { + my $string = shift; + if (is_empty($string)){ + return ""; + } + + $string =~ s/\r//g; + + chomp($string); + $string =~ s/^\s+//g; + $string =~ s/\s+$//g; + + return $string; +} + ################################################################################ # sub sqlWrap(texto) # Elimina comillas y caracteres problematicos y los sustituye por equivalentes diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index 258f820820..660011d6f0 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.750 -%define release 201029 +%define release 201123 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index 7b05aea60c..1de21220a6 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.750 -%define release 201029 +%define release 201123 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index 2712d24fd2..871e768e3c 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.750" -PI_BUILD="201029" +PI_BUILD="201123" MODE=$1 if [ $# -gt 1 ]; then @@ -262,6 +262,7 @@ install () { ln -s /usr/local/bin/pandora_server $DESTDIR$PREFIX/bin ln -s /usr/local/bin/pandora_exec $DESTDIR$PREFIX/bin ln -s /usr/local/bin/tentacle_server $DESTDIR$PREFIX/bin + ln -s /usr/local/bin/tentacle_client $DESTDIR$PREFIX/bin fi fi fi @@ -495,7 +496,9 @@ uninstall () { rm -f $DESTDIR$PANDORA_SERVER 2> /dev/null rm -f $DESTDIR$PREFIX/bin/pandora_server 2> /dev/null rm -f $DESTDIR$PREFIX/bin/pandora_exec 2> /dev/null - rm -f $DESTDIR$PREFIX/bin/tentacle_server 2> /dev/null + # Do not remove tentacle files if agent is still installed... + [ -e $DESTDIR$PREFIX/bin/pandora_agent ] || rm -f $DESTDIR$PREFIX/bin/tentacle_server 2> /dev/null + [ -e $DESTDIR$PREFIX/bin/pandora_agent ] || rm -f $DESTDIR$PREFIX/bin/tentacle_client 2> /dev/null rm -Rf $DESTDIR$PANDORA_HOME rm -f $DESTDIR/etc/cron.hourly/pandora_db rm -f $DESTDIR/etc/logrotate.d/pandora_server diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index e7a1e7ec12..2c55dbf933 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.750 PS201029"; +my $version = "7.0NG.750 PS201123"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index 80771fd543..011225cdec 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.750 PS201029"; +my $version = "7.0NG.750 PS201123"; # save program name for logging my $progname = basename($0); diff --git a/tentacle/tentacle_client b/tentacle/tentacle_client new file mode 100755 index 0000000000..913beda931 --- /dev/null +++ b/tentacle/tentacle_client @@ -0,0 +1,1101 @@ +#!/usr/bin/perl +################################################################################ +# +# Copyright (c) 2007-2008 Ramon Novoa <rnovoa@artica.es> +# Copyright (c) 2007-2008 Artica Soluciones Tecnologicas S.L. +# +# tentacle_client.pl Tentacle Client. See https://pandorafms.com/docs/ for +# protocol description. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# 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. +# +################################################################################ + +package tentacle::client; + +=head1 NAME + +tentacle_client - Tentacle Client + +=head1 VERSION + +Version 0.4.0 + +=head1 USAGE + +tentacle_client [options] [file] [file] ... + +=head1 DESCRIPTION + +B<tentacle_client(1)> is a client for B<tentacle>, a B<client/server> file transfer protocol that aims to be: + +=over + +=item * Secure by design. + +=item * Easy to use. + +=item * Versatile and cross-platform. + +=back + +Tentacle was created to replace more complex tools like SCP and FTP for simple file transfer/retrieval, and switch from authentication mechanisms like .netrc, interactive logins and SSH keys to X.509 certificates. Simple password authentication over a SSL secured connection is supported too. + +The client and server (B<TCP port 41121>) are designed to be run from the command line or called from a shell script, and B<no configuration files are needed>. + +If IO::Socket::INET6 is installed, the tentacle client supports IPv6. + +=cut + +use strict; +use File::Basename; +use Getopt::Std; +use IO::Select; +my $zlib_available = 1; + +eval { + eval "use IO::Compress::Zip qw(zip);1" or die($@); + eval "use IO::Uncompress::Unzip qw(unzip);1" or die($@); +}; +if ($@) { + print_log ("Zip transfer not available, required libraries not found (IO::Compress::Zip, IO::Uncompress::Unzip)."); + $zlib_available = 0; +} + +use Socket (qw(SOCK_STREAM AF_INET AF_INET6)); +my $SOCKET_MODULE = + eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6' + : eval { require IO::Socket::INET } ? 'IO::Socket::INET' + : die $@; + +if ($SOCKET_MODULE eq 'IO::Socket::INET') { + print_log ("IO::Socket::INET6 is not found. IPv6 is disabled."); +} + +# Program version +our $VERSION = '0.4.0'; + +# Server address +my $t_address = '127.0.0.1'; + +# Block size for socket read/write operations in bytes +my $t_block_size = 1024; + +# Log messages, 1 enabled, 0 disabled +my $t_log = 0; + +# Server port +my $t_port = 41121; + +# Do not output error messages, 1 enabled, 0 disabled +my $t_quiet = 0; + +# Proxy address +my $t_proxy_address = ''; + +# Proxy user +my $t_proxy_user = ''; + +# Proxy password +my $t_proxy_pass = ''; + +# Proxy port +my $t_proxy_port = 0; + +# Server password +my $t_pwd = ''; + +# Receive mode, 1 enabled, 0 disabled +my $t_recv = 0; + +# Retries for socket read/write operations +my $t_retries = 3; + +# Select handler +my $t_select; + +# Server socket +my $t_socket; + +# Use SSL, 1 true, 0 false +my $t_ssl = 0; + +# SSL ca certificate file +my $t_ssl_ca = ''; + +# SSL certificate file +my $t_ssl_cert = ''; + +# SSL private key file +my $t_ssl_key = ''; + +# SSL private key file password +my $t_ssl_pwd = ''; + +# Timeout for socket read/write operations in seconds +my $t_timeout = 1; + +# bind ipaddr +my $t_bind_address = undef; + +# Compress data before sending it through the socket. +my $t_zip = 0; + +################################################################################ +## SUB print_help +## Print help screen. +################################################################################ +sub print_help { + + print ("Usage: $0 [options] [file] [file] ...\n\n"); + print ("Tentacle client v$VERSION. See https://pandorafms.com/docs/ for protocol description.\n\n"); + print ("Options:\n"); + print ("\t-a address\tServer address (default $t_address).\n"); + print ("\t-b localaddress\tLocal address to bind.\n"); + print ("\t-c\t\tEnable SSL without a client certificate.\n"); + print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n"); + print ("\t-f ca\t\tVerify that the peer certificate is signed by a ca.\n"); + print ("\t-g\t\tGet files from the server.\n"); + print ("\t-h\t\tShow help.\n"); + print ("\t-k key\t\tOpenSSL private key file.\n"); + print ("\t-p port\t\tServer port (default $t_port).\n"); + print ("\t-q\t\tQuiet. Do now print error messages.\n"); + print ("\t-r number\tNumber of retries for network operations (default $t_retries).\n"); + print ("\t-t time\t\tTime-out for network operations in seconds (default ${t_timeout}s).\n"); + print ("\t-v\t\tBe verbose.\n"); + print ("\t-w\t\tPrompt for OpenSSL private key password.\n"); + print ("\t-x pwd\t\tServer password.\n"); + print ("\t-y proxy\tProxy server string (user:password\@address:port).\n"); + print ("\t-z Compress data.\n\n"); +} + +################################################################################ +## SUB parse_options +## Parse command line options and initialize global variables. +################################################################################ +sub parse_options { + my %opts; + my $tmp; + + # Get options + if (getopts ('a:b:ce:f:ghk:p:qr:t:vwx:y:z', \%opts) == 0 || defined ($opts{'h'})) { + print_help (); + exit 1; + } + + # Address + if (defined ($opts{'a'})) { + $t_address = $opts{'a'}; + if (($t_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + || $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 + || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) && + ($t_address !~ /^[0-9a-f:]+$/o)) { + error ("Address $t_address is not valid."); + } + + } + + # Bind local address + if (defined ($opts{'b'})) { + $t_bind_address = $opts{'b'}; + if (($t_bind_address !~ /^[a-zA-Z\.][a-zA-Z0-9\.\-]+$/ && ($t_bind_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + || $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 + || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) && + ($t_address !~ /^[0-9a-f:]+$/o)) { + error ("Local address $t_bind_address is not valid."); + } + + } + + # Enable SSL without a client certificate + if (defined ($opts{'c'})) { + require IO::Socket::SSL; + $t_ssl = 1; + } + + # Enable SSL + if (defined ($opts{'e'})) { + + if (defined ($opts{'c'})) { + error ("Flags -c and -e can not be used at the same time."); + } + + require IO::Socket::SSL; + + $t_ssl_cert = $opts{'e'}; + if (! -f $t_ssl_cert) { + error ("File $t_ssl_cert does not exist."); + } + + $t_ssl = 1; + } + + # Verify peer certificate + if (defined ($opts{'f'})) { + + if (! defined ($opts{'e'})) { + error ("Flag -e must be set to enable peer certificate verify."); + } + + $t_ssl_ca = $opts{'f'}; + if (! -f $t_ssl_ca) { + error ("File $t_ssl_ca does not exist."); + } + } + + # Get files + if (defined ($opts{'g'})) { + $t_recv = 1; + } + + # SSL private key file + if (defined ($opts{'k'})) { + + if (! defined ($opts{'e'})) { + error ("Flag -e must be set to use a private key file."); + } + + $t_ssl_key = $opts{'k'}; + if (! -f $t_ssl_key) { + error ("File $t_ssl_key does not exist."); + } + } + + # Port + if (defined ($opts{'p'})) { + $t_port = $opts{'p'}; + if ($t_port !~ /^\d+$/ || $t_port < 1 || $t_port > 65535) { + error ("Port $t_port is not valid."); + } + } + + # Quiet mode + if (defined ($opts{'q'})) { + $t_quiet = 1; + } + + # Retries + if (defined ($opts{'r'})) { + $t_retries = $opts{'r'}; + if ($t_retries !~ /^\d+$/ || $t_retries < 1) { + error ("Invalid number of retries for network operations."); + } + } + + # Timeout + if (defined ($opts{'t'})) { + $t_timeout = $opts{'t'}; + if ($t_timeout !~ /^\d+$/ || $t_timeout < 1) { + error ("Invalid timeout for network operations."); + } + } + + # Be verbose + if (defined ($opts{'v'})) { + $t_log = 1; + } + + # SSL private key password + if (defined ($opts{'w'})) { + + if (! defined ($opts{'e'})) { + error ("Flag -k must be set to provide a private key password."); + } + + $t_ssl_pwd = ask_passwd ("Enter private key file password: ", "Enter private key file password again for confirmation: "); + } + + # Server password + if (defined ($opts{'x'})) { + $t_pwd = $opts{'x'}; + } + + # Proxy server + if (defined ($opts{'y'})) { + if ($opts{'y'} !~ /^((.*):(.*)@){0,1}(\S+):(\d+)$/) { + error ("Invalid proxy string: " . $opts{'y'}); + } + + ($t_proxy_user, $t_proxy_pass, $t_proxy_address, $t_proxy_port) = ($2, $3, $4, $5); + $t_proxy_user = '' unless defined ($t_proxy_user); + $t_proxy_pass = '' unless defined ($t_proxy_pass); + if ($t_proxy_port < 1 || $t_proxy_port > 65535) { + error ("Proxy port $t_proxy_port is not valid."); + } + } + + # Compress data + if (defined ($opts{'z'})) { + if ($zlib_available == 1) { + $t_zip = 1; + } + } +} + +################################################################################ +## SUB start_client +## Open the server socket. +################################################################################ +sub start_client { + + # Connect to server + if ($SOCKET_MODULE ne 'IO::Socket::INET') { + if (defined ($t_bind_address)) { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET6, + PeerAddr => $t_address, + PeerPort => $t_port, + LocalAddr => $t_bind_address, + Type => SOCK_STREAM + ); + } + else { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET6, + PeerAddr => $t_address, + PeerPort => $t_port, + Type => SOCK_STREAM + ); + } + } + if (! defined ($t_socket)) { + if (defined ($t_bind_address)) { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET, + PeerAddr => $t_address, + PeerPort => $t_port, + LocalAddr => $t_bind_address, + Type => SOCK_STREAM + ); + } + else { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET, + PeerAddr => $t_address, + PeerPort => $t_port, + Type => SOCK_STREAM + ); + } + } + + if (! defined ($t_socket)) { + error ("Cannot connect to $t_address on port $t_port: $!."); + } + + # Add server socket to select queue + $t_select = IO::Select->new (); + $t_select->add ($t_socket); + + print_log ("Connected to $t_address port $t_port"); +} + +################################################################################ +## SUB start_client_proxy +## Open the server socket. Connects to the Tentacle server through an HTTP proxy. +################################################################################ +sub start_client_proxy { + + # Connect to proxy + if ($SOCKET_MODULE ne 'IO::Socket::INET') { + if (defined ($t_bind_address)) { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET6, + PeerAddr => $t_proxy_address, + PeerPort => $t_proxy_port, + LocalAddr => $t_bind_address, + ); + } + else { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET6, + PeerAddr => $t_proxy_address, + PeerPort => $t_proxy_port, + ); + } + } + if (! defined ($t_socket)) { + if (defined ($t_bind_address)) { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET, + PeerAddr => $t_proxy_address, + PeerPort => $t_proxy_port, + LocalAddr => $t_bind_address, + ); + } + else { + $t_socket = $SOCKET_MODULE->new ( + Domain => AF_INET, + PeerAddr => $t_proxy_address, + PeerPort => $t_proxy_port, + ); + } + } + + if (! defined ($t_socket)) { + error ("Cannot connect to proxy server $t_proxy_address on port $t_proxy_port: $!."); + } + + # Add server socket to select queue + $t_select = IO::Select->new (); + $t_select->add ($t_socket); + + print_log ("Connected to proxy server $t_proxy_address port $t_proxy_port"); + + # Try to CONNECT to the Tentacle server + send_data ("CONNECT " . $t_address . ":" . $t_port . " HTTP/1.0\r\n"); + + # Authenticate to the proxy + if ($t_proxy_user ne '') { + send_data ("Proxy-Authorization: Basic " . base64 ($t_proxy_user . ":" . $t_proxy_pass) . "\r\n"); + } + + send_data ("\r\n"); + + # Check for an HTTP 200 response + my $response = recv_data ($t_block_size); + if ($response !~ m/HTTP.* 200 /) { + my $error = (split (/\r\n/, $response))[0]; + error ("CONNECT error: $error"); + } + + print_log ("Connected to $t_address port $t_port"); +} + +################################################################################ +## SUB stop_client +## Close the server socket. +################################################################################ +sub stop_client { + + $t_socket->shutdown(2); + $t_socket->close (); +} + +################################################################################ +## SUB start_ssl +## Convert the server socket to an IO::Socket::SSL socket. +################################################################################ +sub start_ssl { + my $err; + + if ($t_ssl_cert eq ''){ + IO::Socket::SSL->start_SSL ( + $t_socket, + # No authentication + SSL_verify_mode => 0x00, + ); + } + elsif ($t_ssl_ca eq '') { + IO::Socket::SSL->start_SSL ( + $t_socket, + SSL_cert_file => $t_ssl_cert, + SSL_key_file => $t_ssl_key, + SSL_passwd_cb => sub {return $t_ssl_pwd}, + SSL_use_cert =>'1', + # No authentication + SSL_verify_mode => 0x00, + ); + } + else { + IO::Socket::SSL->start_SSL ( + $t_socket, + SSL_ca_file => $t_ssl_ca, + SSL_cert_file => $t_ssl_cert, + SSL_key_file => $t_ssl_key, + SSL_passwd_cb => sub {return $t_ssl_pwd}, + SSL_use_cert =>'1', + # Verify peer + SSL_verify_mode => 0x01, + ); + } + + $err = IO::Socket::SSL::errstr (); + if ($err ne '') { + error ($err); + } +} + +################################################################################ +## SUB auth_pwd +## Authenticate client with server password. +################################################################################ +sub auth_pwd { + my $command; + my $pwd_digest; + + require Digest::MD5; + + $pwd_digest = Digest::MD5::md5 ($t_pwd); + $pwd_digest = Digest::MD5::md5_hex ($pwd_digest); + + send_data ("PASS $pwd_digest\n"); + + $command = recv_command ($t_block_size); + if ($command !~ /^PASS OK$/) { + error ("Authentication failed."); + } +} + +################################################################################ +## SUB base64 +## Returns the base 64 encoding of a string. +################################################################################ +my @alphabet = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'); +sub base64 { + my $str = shift; + my $str64; + + # Pre-processing + my $msg = unpack ("B*", pack ("A*", $str)); + my $bit_len = length ($msg); + + # Process the message in successive 24-bit chunks + for (my $i = 0; $i < $bit_len; $i += 24) { + my $chunk_len = length (substr ($msg, $i, 24)); + $str64 .= $alphabet[ord (pack ("B8", "00" . substr ($msg, $i, 6)))]; + $str64 .= $alphabet[ord (pack ("B8", "00" . substr ($msg, $i+6, 6)))]; + $str64 .= ($chunk_len <= 12) ? "=" : $alphabet[ord (pack ("B8", "00" . substr ($msg, $i+12, 6)))]; + $str64 .= ($chunk_len <= 18) ? "=" : $alphabet[ord (pack ("B8", "00" . substr ($msg, $i+18, 6)))]; + } + + return $str64; +} + + +################################################################################ +## SUB recv_file +## Receive a file from the server +################################################################################ +sub recv_file { + my $data = ''; + my $file = $_[0]; + my $response; + my $size; + + # Request file + send_data ("RECV <$file>\n"); + + # Wait for server response + $response = recv_command (); + if ($response !~ /^RECV SIZE (\d+)$/) { + error ("Server responded $response."); + } + + $size = $1; + send_data ("RECV OK\n"); + + # Receive file + $data = recv_data_block ($size); + + # Write it to disk + open (FILE, "> $file") || error ("Cannot open file '$file' for writing."); + binmode (FILE); + print (FILE $data); + close (FILE); + + print_log ("Received file '$file'"); +} + +################################################################################ +## SUB zrecv_file +## Receive a compressed file from the server +################################################################################ +sub zrecv_file { + my $data = ''; + my $file = $_[0]; + my $response; + my $size; + my $zdata = ''; + + # Request file + send_data ("ZRECV <$file>\n"); + + # Wait for server response + $response = recv_command (); + if ($response !~ /^ZRECV SIZE (\d+)$/) { + error ("Server responded $response."); + } + + $size = $1; + send_data ("ZRECV OK\n"); + + # Receive file + $zdata = recv_data_block ($size); + if (!unzip(\$zdata => \$data)) { + print_log ("Uncompress error: $IO::Uncompress::Unzip::UnzipError"); + send_data ("ZRECV ERR\n"); + return; + } + + # Write it to disk + open (FILE, "> $file") || error ("Cannot open file '$file' for writing."); + binmode (FILE); + print (FILE $data); + close (FILE); + + print_log ("Received compressed file '$file'"); +} + +################################################################################ +## SUB send_file +## Send a file to the server +################################################################################ +sub send_file { + my $base_name; + my $data = ''; + my $response = ''; + my $retries; + my $file = $_[0]; + my $size; + my $written; + + $base_name = basename ($file); + $size = -s $file; + + # Request to send file + send_data ("SEND <$base_name> SIZE $size\n"); + + print_log ("Request to send file '$base_name' size ${size}b"); + + # Wait for server response + $response = recv_command (); + + # Server rejected the file + if ($response ne "SEND OK") { + send_data ("QUIT\n"); + error ("Server responded $response."); + } + + print_log ("Server responded SEND OK"); + + # Send the file + open (FILE, $file) || error ("Cannot open file '$file' for reading."); + binmode (FILE); + { + local $/ = undef; + $data = <FILE>; + } + send_data ($data); + + close (FILE); + + # Wait for server response + $response = recv_command (); + if ($response ne "SEND OK") { + send_data ("QUIT\n"); + error ("Server responded $response."); + } + + print_log ("File sent"); +} + +################################################################################ +## SUB zsend_file +## Send a file to the server (compressed) +################################################################################ +sub zsend_file { + my $base_name; + my $data = ''; + my $response = ''; + my $retries; + my $file = $_[0]; + my $size; + my $written; + + # Read the file and compress its contents + if (! zip($file => \$data)) { + send_data ("QUIT\n"); + error ("Compression error: $IO::Compress::Zip::ZipError"); + return; + } + + $size = length($data); + $base_name = basename ($file); + + # Request to send file + send_data ("ZSEND <$base_name> SIZE $size\n"); + print_log ("Request to send file '$base_name' size ${size}b (compressed)"); + + # Wait for server response + $response = recv_command (); + + # Server rejected the file + if ($response ne "ZSEND OK") { + send_data ("QUIT\n"); + error ("Server responded $response."); + } + + print_log ("Server responded ZSEND OK"); + send_data ($data); + + # Wait for server response + $response = recv_command (); + if ($response ne "ZSEND OK") { + send_data ("QUIT\n"); + error ("Server responded $response."); + } + + print_log ("File sent"); +} + +################################################################################ +# Common functions +################################################################################ + +################################################################################ +## SUB print_log +## Print log messages. +################################################################################ +sub print_log { + + if ($t_log == 1) { + print (STDOUT "[log] $_[0]\n"); + } +} + +################################################################################ +## SUB error +## Print an error and exit the program. +################################################################################ +sub error { + + if ($t_quiet == 0) { + print (STDERR "[err] $_[0]\n"); + } + + exit 1; +} + +################################################################################ +## SUB recv_data +## Read data from the client socket. Returns the number of bytes read and the +## string of bytes as a two element array. +################################################################################ +sub recv_data { + my $data; + my $read; + my $retries = 0; + my $size = $_[0]; + + while (1) { + + # Try to read data from the socket + if ($t_select->can_read ($t_timeout)) { + + # Read at most $size bytes + $read = sysread ($t_socket, $data, $size); + + # Read error + if (! defined ($read)) { + error ("Read error from " . $t_socket->sockhost () . ": $!."); + } + + # EOF + if ($read == 0) { + error ("Connection from " . $t_socket->sockhost () . " unexpectedly closed."); + } + + return ($read, $data); + } + + # Retry + $retries++; + + # But check for error conditions first + if ($retries > $t_retries) { + error ("Connection from " . $t_socket->sockhost () . " timed out."); + } + } +} + +################################################################################ +## SUB send_data +## Write data to the client socket. +################################################################################ +sub send_data { + my $data = $_[0]; + my $block_size; + my $retries = 0; + my $size; + my $total = 0; + my $written; + + $size = length ($data); + + while (1) { + + # Try to write data to the socket + if ($t_select->can_write ($t_timeout)) { + + $block_size = ($size - $total) > $t_block_size ? $t_block_size : ($size - $total); + $written = syswrite ($t_socket, $data, $block_size, $total); + + # Read error + if (! defined ($written)) { + error ("Connection error from " . $t_socket->sockhost () . ": $!."); + } + + # EOF + if ($written == 0) { + error ("Connection from " . $t_socket->sockhost () . " unexpectedly closed."); + } + + $total += $written; + + # All data was written + if ($total == $size) { + return; + } + # Retry + } else { + $retries++; + if ($retries > $t_retries) { + error ("Connection from " . $t_socket->sockhost () . " timed out."); + } + } + } +} + +################################################################################ +## SUB recv_command +## Read a command from the client, ended by a new line character. +################################################################################ +sub recv_command { + my $buffer; + my $char; + my $command = ''; + my $read; + my $total = 0; + + while (1) { + + ($read, $buffer) = recv_data ($t_block_size); + $command .= $buffer; + $total += $read; + + # Check if the command is complete + $char = chop ($command); + if ($char eq "\n") { + return $command; + } + + $command .= $char; + + # Avoid overflow + if ($total > $t_block_size) { + error ("Received too much data from " . $t_socket->sockhost ()); + } + } +} + +################################################################################ +## SUB recv_data_block +## Read $_[0] bytes of data from the client. +################################################################################ +sub recv_data_block { + my $buffer = ''; + my $data = ''; + my $read; + my $size = $_[0]; + my $total = 0; + + while (1) { + + ($read, $buffer) = recv_data ($size - $total); + $data .= $buffer; + $total += $read; + + # Check if all data has been read + if ($total == $size) { + return $data; + } + } +} + +################################################################################ +## SUB ask_passwd +## Asks the user for a password. +################################################################################ +sub ask_passwd { + my $msg1 = $_[0]; + my $msg2 = $_[1]; + my $pwd1; + my $pwd2; + + require Term::ReadKey; + + # Disable keyboard echo + Term::ReadKey::ReadMode('noecho'); + + # Promt for password + print ($msg1); + $pwd1 = Term::ReadKey::ReadLine(0); + print ("\n$msg2"); + $pwd2 = Term::ReadKey::ReadLine(0); + print ("\n"); + + # Restore original settings + Term::ReadKey::ReadMode('restore'); + + if ($pwd1 ne $pwd2) { + # Call print to bypass quiet mode. + print ("[err] Passwords do not match.\n"); + exit 1; + } + + # Remove the trailing new line character + chop $pwd1; + + return $pwd1; +} + +################################################################################ +# Main +################################################################################ + +my $file; + +# Parse command line options +parse_options (); + +# Check command line arguments +if ($t_recv == 0 && $#ARGV == -1) { + error ("No files to send."); +} + +# Connect to the server +if ($t_proxy_address eq '') { + start_client (); +} else { + start_client_proxy (); +} + +# Start SSL +if ($t_ssl == 1) { + start_ssl (); +} + +# Authenticate with server +if ($t_pwd ne '') { + auth_pwd (); +} + +if ($t_recv == 0) { + # Check that all files exist before trying to send them + foreach $file (@ARGV) { + if (! -f $file) { + error ("File '$file' does not exist."); + } + } + + # Send the files + foreach $file (@ARGV) { + if ($t_zip == 1) { + zsend_file($file); + } else { + send_file ($file); + } + } +} +else { + # Receive the files + foreach $file (@ARGV) { + if ($t_zip == 1) { + zrecv_file ($file); + } else { + recv_file ($file); + } + } +} + +# Tell the server that we are finished +send_data ("QUIT\n"); + +stop_client (); + +exit 0; + + +__END__ + +=head1 OPTIONS + +=over + +=item I<-a address> B<Server address> (default 127.0.0.1). + +=item I<-c> Enable B<SSL> without a client certificate. + +=item I<-e cert> B<OpenSSL certificate> file. Enables SSL. + +=item I<-f ca> Verify that the peer certificate is signed by a B<CA> (Certificate Authority). + +=item I<-g> B<Get> files from the server. + +=item I<-h> Show B<help>. + +=item I<-k key> B<OpenSSL private key> file. + +=item I<-p port> B<Server port> (default I<41121>). + +=item I<-q> B<Quiet>. Do now print error messages. + +=item I<-r number> B<Number of retries> for network operations (default I<3>). + +=item I<-t time> B<Time-out> for network operations in seconds (default I<1s>). + +=item I<-v> Be B<verbose>. + +=item I<-w> Prompt for B<OpenSSL private key password>. + +=item I<-x pwd> B<Server password>. + +=item I<-z> Compress data. + +=back + +=head1 EXIT STATUS + +=over + +=item 0 on Success + +=item 1 on Error + +=back + +=head1 CONFIGURATION + +Tentacle doesn't use any configurationf files, all the configuration is done by the options passed when it's started. + +=head1 DEPENDENCIES + +L<Getopt::Std>, L<IO::Select>, L<IO::Socket::INET>, L<File::Basename> + +=head1 LICENSE + +This is released under the GNU Lesser General Public License. + +=head1 SEE ALSO + +L<Getopt::Std>, L<IO::Select>, L<IO::Socket::INET>, L<File::Basename> + +Protocol description and more info at: L<< https://pandorafms.com/docs/index.php?title=Pandora:Documentation_en:Tentacle >> + +=head1 COPYRIGHT + +Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L + +=cut + diff --git a/tentacle/tentacle_server b/tentacle/tentacle_server new file mode 100755 index 0000000000..feb8ecf9af --- /dev/null +++ b/tentacle/tentacle_server @@ -0,0 +1,1884 @@ +#!/usr/bin/perl +########################################################################## +# Tentacle Server +# See https://pandorafms.com/docs/ for protocol description. +# Tentacle have IANA assigned port tpc/41121 as official port. +########################################################################## +# Copyright (c) 2007-2008 Ramon Novoa <rnovoa@artica.es> +# Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L +# +# tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for +# protocol description. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# 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. +########################################################################## + +package tentacle::server; +=head1 NAME + +tentacle_server - Tentacle Server + +=head1 VERSION + +Version 0.6.1 + +=head1 USAGE + +tentacle_server B<< -s F<storage_directory> >> [I<options>] + +=head1 DESCRIPTION + +B<tentacle_server(1)> is a server for B<tentacle>, a B<client/server> file transfer protocol that aims to be: + +=over + +=item * Secure by design. + +=item * Easy to use. + +=item * Versatile and cross-platform. + +=back + +Tentacle was created to replace more complex tools like SCP and FTP for simple file transfer/retrieval, and switch from authentication mechanisms like .netrc, interactive logins and SSH keys to X.509 certificates. Simple password authentication over a SSL secured connection is supported too. + +The client and server (B<TCP port 41121>) are designed to be run from the command line or called from a shell script, and B<no configuration files are needed>. + +=cut + +use strict; +use warnings; +use Getopt::Std; +use IO::Select; +use IO::Compress::Zip qw(zip $ZipError); +use IO::Uncompress::Unzip qw(unzip $UnzipError); +use threads; +use Thread::Semaphore; +use POSIX ":sys_wait_h"; +use Time::HiRes qw(usleep); +use Scalar::Util qw(refaddr); +use POSIX qw(strftime); + +# Constants for Win32 services. +use constant WIN32_SERVICE_STOPPED => 0x01; +use constant WIN32_SERVICE_RUNNING => 0x04; + +my $t_libwrap_installed = eval { require Authen::Libwrap } ? 1 : 0; + +if ($t_libwrap_installed) { + Authen::Libwrap->import( qw( hosts_ctl STRING_UNKNOWN ) ); +} + +# Log errors, 1 enabled, 0 disabled +my $t_log = 0; + +# Log information, 1 enabled, 0 enabled +my $t_log_hard = 0; + +my $SOCKET_MODULE; +if ($^O eq 'MSWin32') { + # Only support INET on windows + require IO::Socket::INET; + $SOCKET_MODULE = 'IO::Socket::INET'; +} else { + $SOCKET_MODULE = + eval { require IO::Socket::INET6 } ? 'IO::Socket::INET6' + : eval { require IO::Socket::INET } ? 'IO::Socket::INET' + : die $@; +} + +# Service name for Win32. +my $SERVICE_NAME="Tentacle Server"; + +# Service parameters. +my $SERVICE_PARAMS=join(' ', @ARGV); + +# Program version +our $VERSION = '0.6.2'; + +# IPv4 address to listen on +my @t_addresses = ('0', '0.0.0.0'); + +# Block size for socket read/write operations in bytes +my $t_block_size = 1024; + +# Client socket +my $t_client_socket; + +# Run as daemon, 1 true, 0 false +my $t_daemon = 0; + +# Storage directory +my $t_directory = ''; + +# Filters +my @t_filters; + +# Enable (1) or disable (0) insecure mode +my $t_insecure = 0; + +# String containing quoted invalid file name characters +my $t_invalid_chars = '\?\[\]\/\\\=\+\<\>\:\;\'\,\*\~'; + +# Maximum number of simultaneous connections +my $t_max_conn = 10; + +# Maximum file size allowed by the server in bytes +my $t_max_size = 2000000; + +# File overwrite, 1 enabled, 0 disabled +my $t_overwrite = 0; + +# Port to listen on +my $t_port = 41121; + +# Server password +my $t_pwd = ''; + +# Do not output error messages, 1 enabled, 0 disabled +my $t_quiet = 0; + +# Number of retries for socket read/write operations +my $t_retries = 3; + +# Select handler +my $t_select; + +# Semaphore +my $t_sem :shared; + +# Server socket +my @t_server_sockets; + +# Server select handler +my $t_server_select; + +# Use SSL, 1 true, 0 false +my $t_ssl = 0; + +# SSL ca certificate file +my $t_ssl_ca = ''; + +# SSL certificate file +my $t_ssl_cert = ''; + +# SSL private key file +my $t_ssl_key = ''; + +# SSL private key password +my $t_ssl_pwd = ''; + +# Timeout for socket read/write operations in seconds +my $t_timeout = 1; + +# Address to proxy client requests to +my $t_proxy_ip = undef; + +# Port to proxy client requests to +my $t_proxy_port = 41121; + +# Proxy socket +my $t_proxy_socket; + +# Proxy selected handler +my $t_proxy_select; + +# Use libwrap, 1 true, 0 false +my $t_use_libwrap = 0; + +# Program name for libwrap +my $t_program_name = $0; +$t_program_name =~ s/.*\///g; + +# Log file +my $log_file = undef; + +################################################################################ +## SUB print_help +## Print help screen. +################################################################################ +sub print_help { + $" = ','; + + print ("Usage: $0 -s <storage directory> [options]\n\n"); + print ("Tentacle server v$VERSION. See https://pandorafms.com/docs/ for protocol description.\n\n"); + print ("Options:\n"); + print ("\t-a ip_addresses\tIP addresses to listen on (default @t_addresses).\n"); + print ("\t \t(Multiple addresses separated by comma can be defined.)\n"); + print ("\t-c number\tMaximum number of simultaneous connections (default $t_max_conn).\n"); + print ("\t-d\t\tRun as daemon.\n"); + print ("\t-e cert\t\tOpenSSL certificate file. Enables SSL.\n"); + print ("\t-f ca_cert\tVerify that the peer certificate is signed by a ca.\n"); + print ("\t-F config_file\tConfiguration file full path.\n"); + print ("\t-h\t\tShow help.\n"); + print ("\t-I\t\tEnable insecure operations (file listing and moving).\n"); + print ("\t-i\t\tFilters.\n"); + print ("\t-k key\t\tOpenSSL private key file.\n"); + print ("\t-l log_file\t\tFile to write logs.\n"); + print ("\t-m size\t\tMaximum file size in bytes (default ${t_max_size}b).\n"); + print ("\t-o\t\tEnable file overwrite.\n"); + print ("\t-p port\t\tPort to listen on (default $t_port).\n"); + print ("\t-q\t\tQuiet. Do now print error messages.\n"); + print ("\t-r number\tNumber of retries for network opertions (default $t_retries).\n"); + print ("\t-S (install|uninstall|run) Manage the win32 service.\n"); + print ("\t-t time\t\tTime-out for network operations in seconds (default ${t_timeout}s).\n"); + print ("\t-v\t\tBe verbose (display errors).\n"); + print ("\t-V\t\tBe verbose on hard way (display errors and other info).\n"); + print ("\t-w\t\tPrompt for OpenSSL private key password.\n"); + print ("\t-x pwd\t\tServer password.\n"); + print ("\t-b ip_address\tProxy requests to the given address.\n"); + print ("\t-g port\t\tProxy requests to the given port.\n"); + print ("\t-T\t\tEnable tcpwrappers support.\n"); + print ("\t \t\t(To use this option, 'Authen::Libwrap' should be installed.)\n\n"); +} + +################################################################################ +## SUB daemonize +## Turn the current process into a daemon. +################################################################################ +sub daemonize { + my $pid; + + require POSIX; + + chdir ('/') || error ("Cannot chdir to /: $!."); + umask 0; + + open (STDIN, '/dev/null') || error ("Cannot read /dev/null: $!."); + + # Do not be verbose when running as a daemon + open (STDOUT, '>/dev/null') || error ("Cannot write to /dev/null: $!."); + open (STDERR, '>/dev/null') || error ("Cannot write to /dev/null: $!."); + + # Fork + $pid = fork (); + if (! defined ($pid)) { + error ("Cannot fork: $!."); + } + + # Parent + if ($pid != 0) { + exit; + } + + # Child + POSIX::setsid () || error ("Cannot start a new session: $!."); +} + +################################################################################ +## SUB parse_options +## Parse command line options and initialize global variables. +################################################################################ +sub parse_options { + my %opts; + my $CONF = {}; + my $token_value; + my $tmp; + my @t_addresses_tmp; + + # Get options + if (getopts ('a:b:c:de:f:F:g:hIi:k:l:m:op:qr:s:S:t:TvVwx:', \%opts) == 0 || defined ($opts{'h'})) { + print_help (); + exit 1; + } + + # The Win32 service must be installed/uninstalled without checking other parameters. + if (defined ($opts{'S'})) { + my $service_action = $opts{'S'}; + if ($^O ne 'MSWin32') { + error ("Windows services are only available on Win32."); + } else { + eval "use Win32::Daemon"; + die($@) if ($@); + + if ($service_action eq 'install') { + install_service(); + } elsif ($service_action eq 'uninstall') { + uninstall_service(); + } + } + } + + # Configuration file + if (defined($opts{'F'})) { + parse_config_file($opts{'F'}, $CONF); + } + + # Address + $token_value = get_config_value($opts{'a'}, $CONF->{'addresses'}); + if (defined ($token_value)) { + @t_addresses = (); + @t_addresses_tmp = split(/,/, $token_value); + + foreach my $t_address (@t_addresses_tmp) { + $t_address =~ s/^ *(.*?) *$/$1/; + if (($t_address ne '0') && + ($t_address !~ /^[a-zA-Z\.]+$/ && ($t_address !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + || $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 + || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255)) && + ($t_address !~ /^[0-9a-f:]+$/o)) { + error ("Address $t_address is not valid."); + } + push @t_addresses, $t_address; + } + } + + # Maximum simultaneous connections + $token_value = get_config_value($opts{'c'}, $CONF->{'max_connections'}); + if (defined ($token_value)) { + $t_max_conn = $token_value; + if ($t_max_conn !~ /^\d+$/ || $t_max_conn < 1) { + error ("Invalid number of maximum simultaneous connections."); + } + } + + # Run as daemon + $token_value = get_config_value($opts{'d'}, $CONF->{'daemon'}, 1); + if (defined ($token_value)) { + if ($^ eq 'MSWin32') { + error ("-d flag not available for this OS."); + } + + $t_daemon = 1; + } + + # Enable SSL + $token_value = get_config_value($opts{'e'}, $CONF->{'ssl_cert'}); + if (defined ($token_value)) { + + require IO::Socket::SSL; + + $t_ssl_cert = $token_value; + if (! -f $t_ssl_cert) { + error ("File $t_ssl_cert does not exist."); + } + + $t_ssl = 1; + } + + # Verify peer certificate + $token_value = get_config_value($opts{'f'}, $CONF->{'ssl_ca'}); + if (defined ($token_value)) { + $t_ssl_ca = $token_value; + if (! -f $t_ssl_ca) { + error ("File $t_ssl_ca does not exist."); + } + } + + # Insecure mode + $token_value = get_config_value($opts{'I'}, $CONF->{'insecure'}, 1); + if (defined ($token_value)) { + $t_insecure = 1; + } + + # Filters (regexp:dir;regexp:dir...) + $token_value = get_config_value($opts{'i'}, $CONF->{'filters'}); + if (defined ($token_value)) { + my @filters = split (';', $token_value); + foreach my $filter (@filters) { + my ($regexp, $dir) = split (':', $filter); + next unless defined ($regexp) && defined ($dir); + + # Remove any trailing / + my $char = chop ($dir); + $dir .= $char if ($char) ne '/'; + + push(@t_filters, [$regexp, $dir]); + } + } + + # SSL private key file + $token_value = get_config_value($opts{'k'}, $CONF->{'ssl_key'}); + if (defined ($token_value)) { + $t_ssl_key = $token_value; + if (! -f $t_ssl_key) { + error ("File $t_ssl_key does not exist."); + } + } + + # Maximum file size + $token_value = get_config_value($opts{'m'}, $CONF->{'max_size'}); + if (defined ($token_value)) { + $t_max_size = $token_value; + if ($t_max_size !~ /^\d+$/ || $t_max_size < 1) { + error ("Invalid maximum file size."); + } + } + + # File overwrite + $token_value = get_config_value($opts{'o'}, $CONF->{'overwrite'}, 1); + if (defined ($token_value)) { + $t_overwrite = 1; + } + + # Port + $token_value = get_config_value($opts{'p'}, $CONF->{'port'}); + if (defined ($token_value)) { + $t_port = $token_value; + if ($t_port !~ /^\d+$/ || $t_port < 1 || $t_port > 65535) { + error ("Port $t_port is not valid."); + } + } + + # Quiet mode + $token_value = get_config_value($opts{'q'}, $CONF->{'quiet'}, 1); + if (defined ($token_value)) { + $t_quiet = 1; + } + + # Retries + $token_value = get_config_value($opts{'r'}, $CONF->{'retries'}); + if (defined ($token_value)) { + $t_retries = $token_value; + if ($t_retries !~ /^\d+$/ || $t_retries < 1) { + error ("Invalid number of retries for network operations."); + } + } + + # Storage directory + $token_value = get_config_value($opts{'s'}, $CONF->{'directory'}); + if (defined ($token_value)) { + + $t_directory = $token_value; + + # Check that directory exists + if (! -d $t_directory) { + error ("Directory $t_directory does not exist."); + } + + # Check directory permissions + if (! -w $t_directory) { + error ("Cannot write to directory $t_directory."); + } + + # Remove the trailing / if present + $tmp = chop ($t_directory); + if ($tmp ne '/') { + $t_directory .= $tmp; + } + } + else { + $token_value = get_config_value($opts{'b'}, $CONF->{'proxy_ip'}); + if (! defined($token_value)) { + print_help (); + exit 1; + } + } + + # Timeout + $token_value = get_config_value($opts{'t'}, $CONF->{'timeout'}); + if (defined ($token_value)) { + $t_timeout = $token_value; + if ($t_timeout !~ /^\d+$/ || $t_timeout < 1) { + error ("Invalid timeout for network operations."); + } + } + + # Read verbose from config file + if (defined($CONF->{'verbose'})) { + if ($CONF->{'verbose'} eq "1") { + $t_log = 1; + } elsif ($CONF->{'verbose'} eq "2") { + $t_log = 1; + $t_log_hard = 1; + } + } + # Be verbose + if (defined ($opts{'v'})) { + $t_log = 1; + $t_log_hard = 0; + } + # Be verbose hard + if (defined ($opts{'V'})) { + $t_log = 1; + $t_log_hard = 1; + } + + # SSL private key password + $token_value = get_config_value($opts{'w'}, $CONF->{'ssl_password'}, 1); + if (defined ($token_value)) { + $t_ssl_pwd = ask_passwd ("Enter private key file password: ", "Enter private key file password again for confirmation: "); + } + + # Server password + $token_value = get_config_value($opts{'x'}, $CONF->{'password'}); + if (defined ($token_value)) { + $t_pwd = $token_value; + } + + #Proxy IP address + $token_value = get_config_value($opts{'b'}, $CONF->{'proxy_ip'}); + if (defined ($token_value)) { + $t_proxy_ip = $token_value; + if ($t_proxy_ip !~ /^[a-zA-Z\.]+$/ && ($t_proxy_ip !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ + || $1 < 0 || $1 > 255 || $2 < 0 || $2 > 255 + || $3 < 0 || $3 > 255 || $4 < 0 || $4 > 255) && + $t_proxy_ip !~ /^[0-9a-f:]+$/o) { + error ("Proxy address $t_proxy_ip is not valid."); + } + } + + # Proxy Port + $token_value = get_config_value($opts{'g'}, $CONF->{'proxy_port'}); + if (defined ($token_value)) { + $t_proxy_port = $token_value; + if ($t_proxy_port !~ /^\d+$/ || $t_proxy_port < 1 || $t_proxy_port > 65535) { + error ("Proxy port $t_port is not valid."); + } + } + + # TCP wrappers support + $token_value = get_config_value($opts{'T'}, $CONF->{'use_libwrap'}, 1); + if (defined ($token_value)) { + if ($t_libwrap_installed) { + $t_use_libwrap = 1; + } else { + error ("Authen::Libwrap is not installed."); + } + } + + # Win32 service management + if (defined ($opts{'S'})) { + my $service_action = $opts{'S'}; + if ($^O ne 'MSWin32') { + error ("Windows services are only available on Win32."); + } else { + eval "use Win32::Daemon"; + die($@) if ($@); + + if ($service_action eq 'run') { + Win32::Daemon::RegisterCallbacks({ + start => \&callback_start, + running => \&callback_running, + stop => \&callback_stop, + }); + Win32::Daemon::StartService(); + exit 0; + } else { + error("Unknown action: $service_action"); + } + } + } + + # Get the config file + $token_value = get_config_value($opts{'l'}, $CONF->{'log_file'}); + if (defined ($token_value)) { + $log_file = $token_value; + } + + # No command lines config values + + # Get the block size + if (defined ($CONF->{'block_size'})) { + if ($t_port !~ /^\d+$/ || $t_port < 1) { + error ("Invalid block size: " . $CONF->{'block_size'} . "."); + } + $t_block_size = $CONF->{'block_size'}; + } + + # Configuration file invalid chars + if (defined ($CONF->{'invalid_chars'})) { + $t_invalid_chars = $CONF->{'invalid_chars'}; + } +} + +################################################################################ +## SUB parse_config_file +## Get all options from a config file. +################################################################################ +sub parse_config_file { + my ($config_file, $CONF) = @_; + + # File should be writable + if (! -r $config_file) { + print "Configuration file $config_file is not readable.\n"; + return; + } + + # Open the file + my $FH; + if (! open ($FH, "< $config_file")) { + print "Cannot open configuration file $config_file.\n"; + return; + } + + # Read the file and only get the well formed lines + while (<$FH>) { + my $buffer_line = $_; + if ($buffer_line =~ /^[a-zA-Z]/){ # begins with letters + if ($buffer_line =~ m/([\w\-\_\.]+)\s+(.*)/){ + $CONF->{$1} = $2 unless $2 eq ""; + } + } + } + + close ($FH); + return; +} + +################################################################################ +## SUB parse_config_file +## Search in command line options and config hash from configuration file +## to get a value (command line is a priority) +################################################################################ +sub get_config_value { + my ($cmd_value, $conf_value, $bool) = @_; + $bool = 0 unless defined($bool); + + return $cmd_value if defined($cmd_value); + # The boolean type value is 1 or undef (0 should be translated like undefP) + if ($bool && defined($conf_value)) { + return undef if ($conf_value ne "1"); + } + return $conf_value; +} + +################################################################################ +## SUB start_proxy +## Open the proxy server socket. +################################################################################ +sub start_proxy { + + # Connect to server + $t_proxy_socket = $SOCKET_MODULE->new ( + PeerAddr => $t_proxy_ip, + PeerPort => $t_proxy_port, + ); + + if (! defined ($t_proxy_socket)) { + error ("Cannot connect to $t_proxy_ip on port $t_proxy_port: $!."); + } + + # Create proxy selector + $t_proxy_select = IO::Select->new (); + $t_proxy_select->add ($t_proxy_socket); + +} + +################################################################################ +## SUB start_server +## Open the server socket. +################################################################################ +sub start_server { + + my $t_server_socket; + + foreach my $t_address (@t_addresses) { + + $t_server_socket = $SOCKET_MODULE->new ( + Listen => $t_max_conn, + LocalAddr => $t_address, + LocalPort => $t_port, + Proto => 'tcp', + ReuseAddr => 1, + ); + + if (! defined ($t_server_socket)) { + print_log ("Cannot open socket for address $t_address on port $t_port: $!."); + next; + } + + print_log ("Server listening on $t_address port $t_port (press <ctr-c> to stop)"); + + # Say message if tentacle proxy is enable + if (defined ($t_proxy_ip)) { + print_log ("Proxy Mode enable, data will be sent to $t_proxy_ip port $t_proxy_port"); + } + + push @t_server_sockets, $t_server_socket; + } + + if (!@t_server_sockets) { + error ("Cannot open socket for all addresses on port $t_port: $!."); + } + + $t_server_select = IO::Select->new(); + foreach my $t_server_socket (@t_server_sockets){ + $t_server_select->add($t_server_socket); + } +} + +################################################################################ +## SUB send_data_proxy +## Send data to proxy socket. +################################################################################ +sub send_data_proxy { + my $data = $_[0]; + my $block_size; + my $retries = 0; + my $size; + my $total = 0; + my $written; + + $size = length ($data); + + while (1) { + + # Try to write data to the socket + if ($t_proxy_select->can_write ($t_timeout)) { + + $block_size = ($size - $total) > $t_block_size ? $t_block_size : ($size - $total); + $written = syswrite ($t_proxy_socket, $data, $size - $total, $total); + + # Write error + if (! defined ($written)) { + error ("Connection error from " . $t_proxy_socket->sockhost () . ": $!."); + } + + # EOF + if ($written == 0) { + error ("Connection from " . $t_proxy_socket->sockhost () . " unexpectedly closed."); + } + + $total += $written; + + # Check if all data was written + if ($total == $size) { + return; + } + } + # Retry + else { + $retries++; + if ($retries > $t_retries) { + error ("Connection from " . $t_proxy_socket->sockhost () . " timed out."); + } + } + } +} + +################################################################################ +## SUB close_proxy +## Close the proxy socket. +################################################################################ +sub close_proxy { + $t_proxy_socket->shutdown (2); + $t_proxy_socket->close (); +} + +################################################################################ +## SUB stop_server +## Close the server socket. +################################################################################ +sub stop_server { + + foreach my $t_server_socket (@t_server_sockets) { + $t_server_socket->shutdown (2); + $t_server_socket->close (); + } + print_log ("Server going down"); + + exit 0; +} + +################################################################################ +## SUB start_ssl +## Convert the client socket to an IO::Socket::SSL socket. +################################################################################ +sub start_ssl { + my $err; + + if ($t_ssl_ca eq '') { + IO::Socket::SSL->start_SSL ( + $t_client_socket, + SSL_cert_file => $t_ssl_cert, + SSL_key_file => $t_ssl_key, + SSL_passwd_cb => sub {return $t_ssl_pwd}, + SSL_server => 1, + # Verify peer + SSL_verify_mode => 0x01, + ); + } + else { + IO::Socket::SSL->start_SSL ( + $t_client_socket, + SSL_ca_file => $t_ssl_ca, + SSL_cert_file => $t_ssl_cert, + SSL_key_file => $t_ssl_key, + SSL_passwd_cb => sub {return $t_ssl_pwd}, + SSL_server => 1, + # Fail verification if no peer certificate exists + SSL_verify_mode => 0x03, + ); + } + + $err = IO::Socket::SSL::errstr (); + if ($err ne '') { + error ($err); + } + + print_log ("SSL started for " . $t_client_socket->sockhost ()); +} + +################################################################################ +## SUB accept_connections +## Manage incoming connections. +################################################################################ +sub accept_connections { + my $pid; + my $t_server_socket; + + # Ignore SIGPIPE + $SIG{PIPE} = 'IGNORE'; + + # Start server + start_server (); + + # Initialize semaphore + $t_sem = Thread::Semaphore->new ($t_max_conn); + + while (1) { + my @ready = $t_server_select->can_read; + foreach $t_server_socket (@ready) { + + # Accept connection + $t_client_socket = $t_server_socket->accept (); + + if (! defined ($t_client_socket)) { + next if ($! ne ''); # EINTR + error ("accept: $!."); + } + + print_info ("Client connected from " . $t_client_socket->peerhost ()); + + if ($t_use_libwrap && (! hosts_ctl($t_program_name, $t_client_socket))) { + print_log ("Connection from " . $t_client_socket->peerhost() . " is closed by tcpwrappers."); + $t_client_socket->shutdown (2); + $t_client_socket->close(); + } + else { + + # Create a new thread and serve the client + $t_sem->down(); + my $thr = threads->create(\&serve_client); + if (! defined ($thr)) { + error ("Error creating thread: $!."); + } + $thr->detach(); + $t_client_socket->close (); + } + } + + usleep (1000); + } +} + +################################################################################ +## SUB serve_client +## Serve a connected client. +################################################################################ +sub serve_client() { + + eval { + # Add client socket to select queue + $t_select = IO::Select->new (); + $t_select->add ($t_client_socket); + + # Start SSL + if ($t_ssl == 1) { + start_ssl (); + } + + # Authenticate client + if ($t_pwd ne '') { + auth_pwd (); + } + + # Check if proxy mode is enable + if (defined ($t_proxy_ip)) { + serve_proxy_connection (); + } else { + serve_connection (); + } + }; + + $t_client_socket->shutdown (2); + $t_client_socket->close (); + $t_sem->up(); +} + +################################################################################ +## SUB serve_proxy_connection +## Actuate as a proxy between its client and other tentacle server. +################################################################################ +sub serve_proxy_connection { + + # We are a proxy! Start a connection to the Tentacle Server. + start_proxy(); + + # Forward data between the client and the server. + eval { + my $select = IO::Select->new (); + $select->add($t_proxy_socket); + $select->add($t_client_socket); + while (my @ready = $select->can_read()) { + foreach my $socket (@ready) { + if (refaddr($socket) == refaddr($t_client_socket)) { + my ($read, $data) = recv_data($t_block_size); + return unless defined($data); + send_data_proxy($data); + } + else { + my ($read, $data) = recv_data_proxy($t_block_size); + return unless defined($data); + send_data($data); + } + } + } + }; + + # Close the connection to the Tentacle Server. + close_proxy(); +} + +################################################################################ +## SUB serve_connection +## Read and process commands from the client. +################################################################################ +sub serve_connection { + my $command; + + # Read commands + while ($command = recv_command ($t_block_size)) { + + # Client wants to send a file + if ($command =~ /^SEND <(.*)> SIZE (\d+)$/) { + print_info ("Request to send file '$1' size ${2}b from " . $t_client_socket->sockhost ()); + recv_file ($1, $2); + } + # Client wants to receive a file + elsif ($command =~ /^RECV <(.*)>$/) { + print_info ("Request to receive file '$1' from " . $t_client_socket->sockhost ()); + send_file ($1); + } + elsif ($command =~ /^ZSEND <(.*)> SIZE (\d+)$/) { + print_info ("Request to send compressed file '$1' size ${2}b from " . $t_client_socket->sockhost ()); + zrecv_file ($1, $2); + } + # Client wants to receive a file + elsif ($command =~ /^ZRECV <(.*)>$/) { + print_info ("Request to receive compressed file '$1' from " . $t_client_socket->sockhost ()); + zsend_file ($1); + } + # Quit + elsif ($command =~ /^QUIT$/) { + print_info ("Connection closed from " . $t_client_socket->sockhost ()); + last; + } + # File listing. + elsif ($command =~ /^LS <(.*)>$/) { + if ($t_insecure == 0) { + print_info ("Insecure mode disabled. Rejected request to list files matched by filter $1 from " . $t_client_socket->sockhost ()); + last; + } + + print_info ("Request to list files matched by filter $1 from " . $t_client_socket->sockhost ()); + send_file_list ($1); + } + # Client wants to move a file + elsif ($command =~ /^MV <(.*)>$/) { + if ($t_insecure == 0) { + print_info ("Insecure mode disabled. Rejected request to move file $1 from " . $t_client_socket->sockhost ()); + last; + } + + print_info ("Request to move file '$1' from " . $t_client_socket->sockhost ()); + move_file ($1); + } + # Unknown command + else { + print_log ("Unknown command '$command' from " . $t_client_socket->sockhost ()); + last; + } + } +} + +################################################################################ +## SUB auth_pwd +## Authenticate client with server password. +################################################################################ +sub auth_pwd { + my $client_digest; + my $command; + my $pwd_digest; + + require Digest::MD5; + + # Wait for password + $command = recv_command ($t_block_size); + if ($command !~ /^PASS (.*)$/) { + error ("Client " . $t_client_socket->sockhost () . " did not authenticate."); + } + + $client_digest = $1; + $pwd_digest = Digest::MD5::md5 ($t_pwd); + $pwd_digest = Digest::MD5::md5_hex ($pwd_digest); + + if ($client_digest ne $pwd_digest) { + error ("Invalid password from " . $t_client_socket->sockhost () . "."); + } + + print_log ("Client " . $t_client_socket->sockhost () . " authenticated"); + send_data ("PASS OK\n"); +} + +################################################################################ +## SUB recv_file +## Receive a file of size $_[1] and save it in $t_directory as $_[0]. +################################################################################ +sub recv_file { + my $base_name = $_[0]; + my $data = ''; + my $file; + my $size = $_[1]; + + # Check file name + if ($base_name =~ /[$t_invalid_chars]/) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " has an invalid file name"); + send_data ("SEND ERR (invalid file name)\n"); + return; + } + + # Check file size, empty files are not allowed + if ($size < 1 || $size > $t_max_size) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " is too big"); + send_data ("SEND ERR (file is too big)\n"); + return; + } + + # Apply filters + $file = "$t_directory/" . apply_filters ($base_name) . $base_name; + + # Check if file exists + if (-f $file && $t_overwrite == 0) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " already exists"); + send_data ("SEND ERR (file already exists)\n"); + return; + } + + send_data ("SEND OK\n"); + + # Receive file + $data = recv_data_block ($size); + + # Write it to disk + open (FILE, "> $file") || error ("Cannot open file '$file' for writing."); + binmode (FILE); + print (FILE $data); + close (FILE); + + send_data ("SEND OK\n"); + print_info ("Received file '$base_name' size ${size}b from " . $t_client_socket->sockhost ()); +} + +################################################################################ +## SUB zrecv_file +## Receive a compressed file of size $_[1] and save it in $t_directory as $_[0]. +################################################################################ +sub zrecv_file { + my $base_name = $_[0]; + my $data = ''; + my $file; + my $size = $_[1]; + my $zdata = ''; + + # Check file name + if ($base_name =~ /[$t_invalid_chars]/) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " has an invalid file name"); + send_data ("ZSEND ERR (invalid file name)\n"); + return; + } + + # Check file size, empty files are not allowed + if ($size < 1 || $size > $t_max_size) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " is too big"); + send_data ("ZSEND ERR (file is too big)\n"); + return; + } + + # Apply filters + $file = "$t_directory/" . apply_filters ($base_name) . $base_name; + + # Check if file exists + if (-f $file && $t_overwrite == 0) { + print_log ("File '$base_name' size ${size}b from " . $t_client_socket->sockhost () . " already exists"); + send_data ("ZSEND ERR (file already exists)\n"); + return; + } + + send_data ("ZSEND OK\n"); + + # Receive file + $zdata = recv_data_block ($size); + if (!unzip(\$zdata => \$data)) { + print_log ("Uncompress error: $UnzipError"); + send_data ("ZSEND ERR\n"); + return; + } + + # Write it to disk + open (FILE, "> $file") || error ("Cannot open file '$file' for writing."); + binmode (FILE); + print (FILE $data); + close (FILE); + + send_data ("ZSEND OK\n"); + print_info ("Received compressed file '$base_name' size ${size}b from " . $t_client_socket->sockhost ()); +} + +################################################################################ +## SUB send_file +## Send a file to the client +################################################################################ +sub send_file { + my $base_name = $_[0]; + my $data = ''; + my $file; + my $response; + my $size; + + # Check file name + if ($base_name =~ /[$t_invalid_chars]/) { + print_log ("Requested file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name"); + send_data ("RECV ERR (file has an invalid file name)\n"); + return; + } + + # Apply filters + $file = "$t_directory/" . apply_filters ($base_name) . $base_name; + + # Check if file exists + if (! -f $file) { + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " does not exist"); + send_data ("RECV ERR (file does not exist)\n"); + return; + } + + $size = -s $file; + send_data ("RECV SIZE $size\n"); + + # Wait for client response + $response = recv_command ($t_block_size); + if ($response ne "RECV OK") { + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " not sent"); + return; + } + + # Send the file + open (FILE, $file) || error ("Cannot open file '$file' for reading."); + binmode (FILE); + { + local $/ = undef; + $data = <FILE>; + } + + send_data ($data); + close (FILE); + + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent"); +} + +################################################################################ +## SUB zsend_file +## Send a file to the client +################################################################################ +sub zsend_file { + my $base_name = $_[0]; + my $data = ''; + my $file; + my $response; + my $size; + + # Check file name + if ($base_name =~ /[$t_invalid_chars]/) { + print_log ("Requested compressed file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name"); + send_data ("ZRECV ERR (file has an invalid file name)\n"); + return; + } + + # Apply filters + $file = "$t_directory/" . apply_filters ($base_name) . $base_name; + + # Check if file exists + if (! -f $file) { + print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " does not exist"); + send_data ("ZRECV ERR (file does not exist)\n"); + return; + } + + # Read the file and compress its contents + if (! zip($file => \$data)) { + send_data ("QUIT\n"); + error ("Compression error: $ZipError"); + return; + } + + $size = length($data); + send_data ("ZRECV SIZE $size\n"); + + # Wait for client response + $response = recv_command ($t_block_size); + if ($response ne "ZRECV OK") { + print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " not sent"); + return; + } + + # Send the file + send_data ($data); + + print_log ("Requested compressed '$file' from " . $t_client_socket->sockhost () . " sent"); +} + +################################################################################ +# Common functions +################################################################################ + +################################################################################ +## SUB print_log +## Print log messages. +################################################################################ +sub print_log($) { + + my ($msg) = @_; + + return unless ($t_log == 1); + + my $fh = *STDOUT; + if (defined($log_file)) { + open($fh, ">>", $log_file) || die("Starting log failed: $!.\n"); + } + + print ($fh strftime ("%Y-%m-%d %H:%M:%S", localtime()) . "[log]$msg.\n"); + + close ($fh) if (defined($log_file)); + +} + +################################################################################ +## SUB print_log +## Print log messages. +################################################################################ +sub print_info($) { + + my ($msg) = @_; + + return unless ($t_log_hard == 1); + + my $fh = *STDOUT; + if (defined($log_file)) { + open($fh, ">>", $log_file) || die("Starting log failed: $!.\n"); + } + + print ($fh strftime ("%Y-%m-%d %H:%M:%S", localtime()) . "[info]$msg.\n"); + + close ($fh) if (defined($log_file)); + +} + +################################################################################ +## SUB error +## Print an error and exit the program. +################################################################################ +sub error { + + my ($msg) = @_; + + return unless ($t_quiet == 0); + + my $fh = *STDERR; + if (defined($log_file)) { + open($fh, ">>", $log_file) || die("$!\n"); + } + + print ($fh strftime ("%Y-%m-%d %H:%M:%S", localtime()) . "[err]$msg\n"); + + close ($fh) if (defined($log_file)); + + die("\n"); +} + +################################################################################ +## SUB move_file +## Send a file to the client and delete it +################################################################################ +sub move_file { + my $base_name = $_[0]; + my $data = ''; + my $file; + my $response; + my $size; + + # Check file name + if ($base_name =~ /[$t_invalid_chars]/) { + print_log ("Requested file '$base_name' from " . $t_client_socket->sockhost () . " has an invalid file name"); + send_data ("MV ERR\n"); + return; + } + + # Apply filters + $file = "$t_directory/" . apply_filters ($base_name) . $base_name; + + # Check if file exists + if (! -f $file) { + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " does not exist"); + send_data ("MV ERR\n"); + return; + } + + $size = -s $file; + send_data ("MV SIZE $size\n"); + + # Wait for client response + $response = recv_command ($t_block_size); + if ($response ne "MV OK") { + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " not sent"); + return; + } + + # Send the file + open (FILE, $file) || error ("Cannot open file '$file' for reading."); + binmode (FILE); + + while ($data = <FILE>) { + send_data ($data); + } + + close (FILE); + unlink($file); + + print_log ("Requested file '$file' from " . $t_client_socket->sockhost () . " sent and deleted"); +} + +################################################################################ +## SUB send_file_list +## Send a list of files to the client after applying the given filter. +################################################################################ +sub send_file_list { + my $filter = $_[0]; + my $data = ''; + my $dir; + my $dh; + my $response; + my $size; + + # Check file name + if ($filter =~ /[$t_invalid_chars]/) { + print_log ("Invalid file listing filter '$filter' from " . $t_client_socket->sockhost ()); + send_data ("LS ERR\n"); + return; + } + + # Apply filters + $dir = "$t_directory/" . apply_filters ($filter); + + # Open the directory. + if (! opendir ($dh, $dir)) { + print_log ("Error opening directory $dir as requested from " . $t_client_socket->sockhost () . ": $!"); + send_data ("LS ERR\n"); + return; + } + + # List files. + while (my $file = readdir ($dh)) { + next if ($file =~ /[$t_invalid_chars]/); # Only list files valid for Tentacle. + $data .= "$file\n"; + } + closedir $dh; + + $size = length ($data); + send_data ("LS SIZE $size\n"); + + # Wait for client response + $response = recv_command ($t_block_size); + if ($response ne "LS OK") { + print_log ("Requested directory listing from " . $t_client_socket->sockhost () . " not sent"); + return; + } + + send_data ($data); + + print_log ("Requested directory listing from " . $t_client_socket->sockhost () . " sent"); +} + +################################################################################ +## SUB recv_data_proxy +## Recv data from proxy socket. +################################################################################ +sub recv_data_proxy { + my $data; + my $read; + my $retries = 0; + my $size = $_[0]; + + while (1) { + + # Try to read data from the socket + if ($t_proxy_select->can_read ($t_timeout)) { + + # Read at most $size bytes + $read = sysread ($t_proxy_socket, $data, $size); + + # Read error + if (! defined ($read)) { + error ("Read error from " . $t_proxy_socket->sockhost () . ": $!."); + } + + # EOF + if ($read == 0) { + error ("Connection from " . $t_proxy_socket->sockhost () . " unexpectedly closed."); + } + + return ($read, $data); + } + + # Retry + $retries++; + + # But check for error conditions first + if ($retries > $t_retries) { + error ("Connection from " . $t_proxy_socket->sockhost () . " timed out."); + } + } +} +################################################################################ +## SUB recv_data +## Read data from the client socket. Returns the number of bytes read and the +## string of bytes as a two element array. +################################################################################ +sub recv_data { + my $data; + my $read; + my $retries = 0; + my $size = $_[0]; + + while (1) { + + # Try to read data from the socket + if ($t_select->can_read ($t_timeout)) { + + # Read at most $size bytes + $read = sysread ($t_client_socket, $data, $size); + + # Read error + if (! defined ($read)) { + error ("Read error from " . $t_client_socket->sockhost () . ": $!."); + } + + # EOF + if ($read == 0) { + error ("Connection from " . $t_client_socket->sockhost () . " unexpectedly closed."); + } + + return ($read, $data); + } + + # Retry + $retries++; + + # But check for error conditions first + if ($retries > $t_retries) { + error ("Connection from " . $t_client_socket->sockhost () . " timed out."); + } + } +} + +################################################################################ +## SUB send_data +## Write data to the client socket. +################################################################################ +sub send_data { + my $data = $_[0]; + my $block_size; + my $retries = 0; + my $size; + my $total = 0; + my $written; + + $size = length ($data); + + while (1) { + + # Try to write data to the socket + if ($t_select->can_write ($t_timeout)) { + + $block_size = ($size - $total) > $t_block_size ? $t_block_size : ($size - $total); + $written = syswrite ($t_client_socket, $data, $block_size, $total); + + # Write error + if (! defined ($written)) { + error ("Connection error from " . $t_client_socket->sockhost () . ": $!."); + } + + # EOF + if ($written == 0) { + error ("Connection from " . $t_client_socket->sockhost () . " unexpectedly closed."); + } + + $total += $written; + + # Check if all data was written + if ($total == $size) { + return; + } + } + # Retry + else { + $retries++; + if ($retries > $t_retries) { + error ("Connection from " . $t_client_socket->sockhost () . " timed out."); + } + } + } +} + +################################################################################ +## SUB recv_command +## Read a command from the client, ended by a new line character. +################################################################################ +sub recv_command { + my $buffer; + my $char; + my $command = ''; + my $read; + my $total = 0; + + while (1) { + + ($read, $buffer) = recv_data ($t_block_size); + $command .= $buffer; + $total += $read; + + # Check if the command is complete + $char = chop ($command); + if ($char eq "\n") { + return $command; + } + + $command .= $char; + + # Avoid overflow + if ($total > $t_block_size) { + error ("Received too much data from " . $t_client_socket->sockhost () . "."); + } + } +} + +################################################################################ +## SUB recv_data_block +## Read $_[0] bytes of data from the client. +################################################################################ +sub recv_data_block { + my $buffer = ''; + my $data = ''; + my $read; + my $size = $_[0]; + my $total = 0; + + while (1) { + + ($read, $buffer) = recv_data ($size - $total); + $data .= $buffer; + $total += $read; + + # Check if all data has been read + if ($total == $size) { + return $data; + } + } +} + +################################################################################ +## SUB ask_passwd +## Asks the user for a password. +################################################################################ +sub ask_passwd { + my $msg1 = $_[0]; + my $msg2 = $_[1]; + my $pwd1; + my $pwd2; + + require Term::ReadKey; + + # Disable keyboard echo + Term::ReadKey::ReadMode('noecho'); + + # Promt for password + print ($msg1); + $pwd1 = Term::ReadKey::ReadLine(0); + print ("\n$msg2"); + $pwd2 = Term::ReadKey::ReadLine(0); + print ("\n"); + + # Restore original settings + Term::ReadKey::ReadMode('restore'); + + if ($pwd1 ne $pwd2) { + print ("Error: passwords do not match.\n"); + exit 1; + } + + # Remove the trailing new line character + chop $pwd1; + + return $pwd1; +} + +################################################################################ +## SUB apply_filters +## Applies filters to the given file. +################################################################################ +sub apply_filters ($) { + my ($file_name) = @_; + + foreach my $filter (@t_filters) { + my ($regexp, $dir) = @{$filter}; + if ($file_name =~ /$regexp/) { + print_log ("File '$file_name' matches filter '$regexp' (changing to directory '$dir')"); + return $dir . '/'; + } + } + + return ''; +} + +################################################################################ +## SUB install_service +## Install the Windows service. +################################################################################ +sub install_service() { + + my $service_path = $0; + my $service_params = $SERVICE_PARAMS; + + # Change the service parameter from 'install' to 'run'. + $service_params =~ s/\-S\s+\S+/\-S run/; + + my %service_hash = ( + machine => '', + name => 'TENTACLESRV', + display => $SERVICE_NAME, + path => $service_path, + user => '', + pwd => '', + description => 'Tentacle Server http://sourceforge.net/projects/tentacled/', + parameters => $service_params + ); + + if (Win32::Daemon::CreateService(\%service_hash)) { + print "Successfully added.\n"; + exit 0; + } else { + print "Failed to add service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; + } +} + +################################################################################ +## SUB uninstall_service +## Install the Windows service. +################################################################################ +sub uninstall_service() { + if (Win32::Daemon::DeleteService('', 'TENTACLESRV')) { + print "Successfully deleted.\n"; + exit 0; + } else { + print "Failed to delete service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; + } +} + +################################################################################ +## SUB callback_running +## Windows service callback function for the running event. +################################################################################ +sub callback_running { + + if (Win32::Daemon::State() == WIN32_SERVICE_RUNNING) { + } +} + +################################################################################ +## SUB callback_start +## Windows service callback function for the start event. +################################################################################ +sub callback_start { + + # Accept_connections (); + my $thr = threads->create(\&accept_connections); + if (!defined($thr)) { + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); + return; + } + $thr->detach(); + + Win32::Daemon::State(WIN32_SERVICE_RUNNING); +} + +################################################################################ +## SUB callback_stop +## Windows service callback function for the stop event. +################################################################################ +sub callback_stop { + + foreach my $t_server_socket (@t_server_sockets) { + $t_server_socket->shutdown (2); + $t_server_socket->close (); + } + + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); +} + + +################################################################################ +## SUB check_ssleay_version +## Print a message if the installed version of Net::SSLeay may leak memory. +################################################################################ +sub check_ssleay_version { + eval { + require Net::SSLeay; + return unless defined($Net::SSLeay::VERSION) && $Net::SSLeay::VERSION =~ m/^(\d+)\.(\d+)/ && $1 <= 1 && $2 < 88; + print_log ("Net::SSLeay version $Net::SSLeay::VERSION detected. Versions prior to 1.88 may leak memory. To upgrade it see: https://metacpan.org/pod/Net::SSLeay"); + }; +} + +################################################################################ +# Main +################################################################################ + +# Never run as root +if ($> == 0 && $^O ne 'MSWin32') { + print ("Error: for safety reasons $0 cannot be run with root privileges.\n"); + exit 1; +} + +# Parse command line options +parse_options (); + +# Check command line arguments +if ($#ARGV != -1) { + print_help (); + exit 1; +} + +check_ssleay_version() if $t_ssl == 1; + +# Show IPv6 status +if ($SOCKET_MODULE eq 'IO::Socket::INET') { + print_log ("IO::Socket::INET6 is not found. IPv6 is disabled."); +} + +# Run as daemon? +if ($t_daemon == 1 && $^O ne 'MSWin32') { + daemonize (); +} + +# Handle ctr-c +if ($^O eq 'MSWin32') { + no warnings; + $SIG{INT2} = \&stop_server; + use warnings; +} +else { + $SIG{INT} = \&stop_server; +} + +# Accept connections +accept_connections(); + +__END__ + +=head1 REQUIRED ARGUMENTES + +=over + +=item B<< -s F<storage_directory> >> Root directory to store the files received by the server + +=back + +=head1 OPTIONS + +=over + +=item I<-a ip_address> Address to B<listen> on (default I<0.0.0.0>). + +=item I<-c number> B<Maximum> number of simultaneous B<connections> (default I<10>). + +=item I<-d> Run as B<daemon>. + +=item I<-e cert> B<OpenSSL certificate> file. Enables SSL. + +=item I<-f ca_cert> Verify that the peer certificate is signed by a B<CA>. + +=item I<-h> Show B<help>. + +=item I<-i> B<Filters>. + +=item I<-k key> B<OpenSSL private key> file. + +=item I<-m size> B<Maximum file size> in bytes (default I<2000000b>). + +=item I<-o> Enable file B<overwrite>. + +=item I<-p port> B<Port to listen> on (default I<41121>). + +=item I<-q> B<Quiet>. Do now print error messages. + +=item I<-r number> B<Number of retries> for network opertions (default I<3>). + +=item I<-t time> B<Time-out> for network operations in B<seconds> (default I<1s>). + +=item I<-v> Be B<verbose>. + +=item I<-w> Prompt for B<OpenSSL private key password>. + +=item I<-x> pwd B<Server password>. + +=back + +=head1 EXIT STATUS + +=over + +=item 0 on Success + +=item 1 on Error + +=back + +=head1 CONFIGURATION + +Tentacle doesn't use any configurationf files, all the configuration is done by the options passed when it's started. + +=head1 DEPENDENCIES + +L<Getopt::Std>, L<IO::Select>, L<IO::Socket::INET>, L<Thread::Semaphore>, L<POSIX> + + +=head1 LICENSE + +This is released under the GNU Lesser General Public License. + +=head1 SEE ALSO + +L<Getopt::Std>, L<IO::Select>, L<IO::Socket::INET>, L<Thread::Semaphore>, L<POSIX> + +Protocol description and more info at: L<< https://pandorafms.com/docs/index.php?title=Pandora:Documentation_en:Tentacle >> + +=head1 COPYRIGHT + +Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L + +=cut +