diff --git a/pandora_agents/pc/tentacle_server b/pandora_agents/pc/tentacle_server index d945a134e8..4458237003 100755 --- a/pandora_agents/pc/tentacle_server +++ b/pandora_agents/pc/tentacle_server @@ -5,7 +5,7 @@ # Tentacle have IANA assigned port tpc/41121 as official port. ########################################################################## # Copyright (c) 2007-2008 Ramon Novoa -# Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L +# Copyright (c) 2005-2022 Artica Soluciones Tecnologicas S.L # # tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for # protocol description. @@ -1740,6 +1740,19 @@ sub callback_stop { 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 ################################################################################ @@ -1753,12 +1766,20 @@ if ($> == 0 && $^O ne 'MSWin32') { # Parse command line options parse_options (); +# Try to open the log file. +if (defined($log_file)) { + open(my $fh, ">>", $log_file) || die("Error opening the log file '$log_file': $!.\n"); + close($fh); +} + # 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."); diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 4018039f20..afbea35741 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-agent-unix -Version: 7.0NG.765-221014 +Version: 7.0NG.765-221026 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 44889d501d..3d6a014c29 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.765-221014" +pandora_version="7.0NG.765-221026" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 2f5e6417a9..8f762f9a65 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1015,7 +1015,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.765'; -use constant AGENT_BUILD => '221014'; +use constant AGENT_BUILD => '221026'; # 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 2fffcc1d23..686f414780 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.765 -%define release 221014 +%define release 221026 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 51c0844ab9..b9eab464a0 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.765 -%define release 221014 +%define release 221026 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 4221c2f2b2..a59808a885 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.765" -PI_BUILD="221014" +PI_BUILD="221026" OS_NAME=`uname -s` FORCE=0 diff --git a/pandora_agents/unix/tentacle_server b/pandora_agents/unix/tentacle_server index d945a134e8..4458237003 100755 --- a/pandora_agents/unix/tentacle_server +++ b/pandora_agents/unix/tentacle_server @@ -5,7 +5,7 @@ # Tentacle have IANA assigned port tpc/41121 as official port. ########################################################################## # Copyright (c) 2007-2008 Ramon Novoa -# Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L +# Copyright (c) 2005-2022 Artica Soluciones Tecnologicas S.L # # tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for # protocol description. @@ -1740,6 +1740,19 @@ sub callback_stop { 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 ################################################################################ @@ -1753,12 +1766,20 @@ if ($> == 0 && $^O ne 'MSWin32') { # Parse command line options parse_options (); +# Try to open the log file. +if (defined($log_file)) { + open(my $fh, ">>", $log_file) || die("Error opening the log file '$log_file': $!.\n"); + close($fh); +} + # 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."); diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index 2f669dbbf9..a6bcc390be 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{221014} +{221026} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 30860fc1d2..2baf3ae615 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.765 Build 221014") +#define PANDORA_VERSION ("7.0NG.765 Build 221026") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index b6193a0aed..61bf9e4d76 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.765(Build 221014))" + VALUE "ProductVersion", "(7.0NG.765(Build 221026))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 3019355c3f..1f7e782c96 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-console -Version: 7.0NG.765-221014 +Version: 7.0NG.765-221026 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 f532ec4147..a517b126f8 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.765-221014" +pandora_version="7.0NG.765-221026" package_pear=0 package_pandora=1 diff --git a/pandora_console/ajax.php b/pandora_console/ajax.php index 8b98d1c34a..bea9dfc771 100644 --- a/pandora_console/ajax.php +++ b/pandora_console/ajax.php @@ -110,12 +110,13 @@ $auth_class = io_safe_output( $page = (string) get_parameter('page'); $page = safe_url_extraclean($page); $page .= '.php'; +$page = realpath($page); $public_hash = get_parameter('auth_hash', false); $public_login = false; if (false === ((bool) get_parameter('doLogin', false) === true - && $page === 'include/rest-api/index.php') + && $page === realpath('include/rest-api/index.php')) ) { // Check user. if (class_exists($auth_class) === false || $public_hash === false) { diff --git a/pandora_console/extras/delete_files/delete_files.txt b/pandora_console/extras/delete_files/delete_files.txt index f9acc8ade4..96223ccd69 100644 --- a/pandora_console/extras/delete_files/delete_files.txt +++ b/pandora_console/extras/delete_files/delete_files.txt @@ -1666,3 +1666,4 @@ godmode/um_client/vendor/sebastian/object-enumerator godmode/um_client/vendor/sebastian godmode/um_client/vendor update_manager_client/resources/styles/pandora.css +enterprise/meta/general/upload_head_image.php diff --git a/pandora_console/extras/mr/58.sql b/pandora_console/extras/mr/58.sql index e5408c52b7..382c4e8c18 100644 --- a/pandora_console/extras/mr/58.sql +++ b/pandora_console/extras/mr/58.sql @@ -2,7 +2,11 @@ START TRANSACTION; ALTER TABLE `tlayout` ADD COLUMN `maintenance_mode` TEXT; +ALTER TABLE `tusuario` ADD COLUMN `auth_token_secret` VARCHAR(45) DEFAULT NULL; + ALTER TABLE `tmodule_inventory` ADD COLUMN `script_mode` INT NOT NULL DEFAULT 2; ALTER TABLE `tmodule_inventory` ADD COLUMN `script_path` VARCHAR(1000) DEFAULT ''; +ALTER TABLE `tevent_filter` ADD COLUMN `search_recursive_groups` INT NOT NULL DEFAULT 0; + COMMIT; diff --git a/pandora_console/godmode/agentes/configurar_agente.php b/pandora_console/godmode/agentes/configurar_agente.php index af29579055..7aca913aeb 100644 --- a/pandora_console/godmode/agentes/configurar_agente.php +++ b/pandora_console/godmode/agentes/configurar_agente.php @@ -181,7 +181,7 @@ $module_macros = []; // Create agent. if ($create_agent) { $mssg_warning = 0; - $alias_safe_output = io_safe_output(get_parameter('alias', '')); + $alias_safe_output = strip_tags(io_safe_output(get_parameter('alias', ''))); $alias = io_safe_input(trim(preg_replace('/[\/\\\|%#&$]/', '', $alias_safe_output))); $alias_as_name = (int) get_parameter_post('alias_as_name', 0); $direccion_agente = (string) get_parameter_post('direccion', ''); @@ -935,7 +935,7 @@ if ($update_agent) { $mssg_warning = 0; $id_agente = (int) get_parameter_post('id_agente'); $nombre_agente = str_replace('`', '‘', (string) get_parameter_post('agente', '')); - $alias_safe_output = io_safe_output(get_parameter('alias', '')); + $alias_safe_output = strip_tags(io_safe_output(get_parameter('alias', ''))); $alias = io_safe_input(trim(preg_replace('/[\/\\\|%#&$]/', '', $alias_safe_output))); $alias_as_name = (int) get_parameter_post('alias_as_name', 0); $direccion_agente = (string) get_parameter_post('direccion', ''); @@ -1047,7 +1047,7 @@ if ($update_agent) { // If there is an agent with the same name, but a different ID. } - if ($unique_ip && $direccion_agente != '') { + if ($direccion_agente !== $address_list && (bool) $unique_ip === true && $direccion_agente != '') { $sql = 'SELECT direccion FROM tagente WHERE direccion = "'.$direccion_agente.'"'; $exists_ip = db_get_row_sql($sql); } diff --git a/pandora_console/godmode/agentes/module_manager.php b/pandora_console/godmode/agentes/module_manager.php index 6cfa2685b4..b63392ac4c 100644 --- a/pandora_console/godmode/agentes/module_manager.php +++ b/pandora_console/godmode/agentes/module_manager.php @@ -40,16 +40,7 @@ require_once $config['homedir'].'/include/functions_modules.php'; require_once $config['homedir'].'/include/functions_agents.php'; require_once $config['homedir'].'/include/functions_servers.php'; -$search_string = io_safe_output( - urldecode( - trim( - get_parameter( - 'search_string', - '' - ) - ) - ) -); +$search_string = get_parameter('search_string'); global $policy_page; diff --git a/pandora_console/godmode/agentes/planned_downtime.editor.php b/pandora_console/godmode/agentes/planned_downtime.editor.php index cec18a21ca..ed41aee0ef 100644 --- a/pandora_console/godmode/agentes/planned_downtime.editor.php +++ b/pandora_console/godmode/agentes/planned_downtime.editor.php @@ -1104,11 +1104,7 @@ $table->data[1][0] = __('Available agents'); $table->data[1][1] = html_print_select($agents, 'id_agents[]', -1, '', _('Any'), -2, true, true, true, '', false, 'min-width: 250px;width: 70%;'); -if ($type_downtime != 'quiet') { - echo ''; } diff --git a/pandora_console/include/functions_reporting.php b/pandora_console/include/functions_reporting.php index ab1e64cfcf..54e0173fa2 100755 --- a/pandora_console/include/functions_reporting.php +++ b/pandora_console/include/functions_reporting.php @@ -4011,7 +4011,7 @@ function reporting_groups_nodes($content) } // Grouped. - $filters['group_rep'] = 1; + $filters['group_rep'] = EVENT_GROUP_REP_EVENTS; $events = Event::search( [ diff --git a/pandora_console/include/functions_reporting_html.php b/pandora_console/include/functions_reporting_html.php index 029b0d70b6..cd764dbf32 100644 --- a/pandora_console/include/functions_reporting_html.php +++ b/pandora_console/include/functions_reporting_html.php @@ -1944,7 +1944,16 @@ function reporting_html_inventory($table, $item, $pdf=0) $table1->head[$k] = $k; $table1->headstyle[$k] = 'text-align: left'; $table1->cellstyle[$str_key][$k] = 'text-align: left;'; - $table1->data[$str_key][$k] = $v; + if ($pdf === 0) { + $table1->data[$str_key][$k] = $v; + } else { + // Workaround to prevent table columns from growing indefinitely in PDFs. + $table1->data[$str_key][$k] = preg_replace( + '/([^\s]{30})(?=[^\s])/', + '$1'.'
', + $v + ); + } } } } diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index 632069a397..6ae90f29ef 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -3402,7 +3402,7 @@ function ui_print_datatable(array $parameters) $filter .= ''; $filter .= '
'; - if (isset($parameters['form']['no_toggle']) === false && ($parameters['form']['no_toggle'] !== true)) { + if (isset($parameters['form']['no_toggle']) === false) { $filter = ui_toggle( $filter, __('Filter'), @@ -3466,7 +3466,10 @@ function ui_print_datatable(array $parameters) foreach ($names as $column) { if (is_array($column)) { $table .= ''.__($column['text']); $table .= $column['extra']; $table .= ''; @@ -6510,7 +6513,7 @@ function ui_print_breadcrums($tab_name) /** * Show last comment * - * @param array $comments array with comments + * @param string $comments String with comments. * * @return string HTML string with the last comment of the events. */ @@ -6534,31 +6537,45 @@ function ui_print_comments($comments) foreach ($comments_array as $comm) { // Show the comments more recent first. if (is_array($comm)) { - $last_comment[] = array_reverse($comm); + $order_utimestamp = array_reduce( + $comm, + function ($carry, $item) { + $carry[$item['utimestamp']] = $item; + return $carry; + } + ); + + $key_max_utimestamp = max(array_keys($order_utimestamp)); + + $last_comment = $order_utimestamp[$key_max_utimestamp]; } } + if (empty($last_comment) === true) { + return ''; + } + // Only show the last comment. If commment its too long,the comment will short with ... // If $config['prominent_time'] is timestamp the date show Month, day, hour and minutes. // Else show comments hours ago - if ($last_comment[0][0]['action'] != 'Added comment') { - $last_comment[0][0]['comment'] = $last_comment[0][0]['action']; + if ($last_comment['action'] != 'Added comment') { + $last_comment['comment'] = $last_comment['action']; } - $short_comment = substr($last_comment[0][0]['comment'], 0, 20); + $short_comment = substr($last_comment['comment'], 0, 20); if ($config['prominent_time'] == 'timestamp') { - $comentario = ''.date($config['date_format'], $last_comment[0][0]['utimestamp']).' ('.$last_comment[0][0]['id_user'].'): '.$last_comment[0][0]['comment'].''; + $comentario = ''.date($config['date_format'], $last_comment['utimestamp']).' ('.$last_comment['id_user'].'): '.$last_comment['comment'].''; if (strlen($comentario) > '200px') { - $comentario = ''.date($config['date_format'], $last_comment[0][0]['utimestamp']).' ('.$last_comment[0][0]['id_user'].'): '.$short_comment.'...'; + $comentario = ''.date($config['date_format'], $last_comment['utimestamp']).' ('.$last_comment['id_user'].'): '.$short_comment.'...'; } } else { - $rest_time = (time() - $last_comment[0][0]['utimestamp']); + $rest_time = (time() - $last_comment['utimestamp']); $time_last = (($rest_time / 60) / 60); - $comentario = ''.number_format($time_last, 0).'  Hours  ('.$last_comment[0][0]['id_user'].'): '.$last_comment[0][0]['comment'].''; + $comentario = ''.number_format($time_last, 0).'  Hours  ('.$last_comment['id_user'].'): '.$last_comment['comment'].''; if (strlen($comentario) > '200px') { - $comentario = ''.number_format($time_last, 0).'  Hours  ('.$last_comment[0][0]['id_user'].'): '.$short_comment.'...'; + $comentario = ''.number_format($time_last, 0).'  Hours  ('.$last_comment['id_user'].'): '.$short_comment.'...'; } } diff --git a/pandora_console/include/functions_users.php b/pandora_console/include/functions_users.php index 966fc5446a..17dc7911ee 100755 --- a/pandora_console/include/functions_users.php +++ b/pandora_console/include/functions_users.php @@ -235,27 +235,31 @@ function groups_combine_acl($acl_group_a, $acl_group_b) } $acl_list = [ - 'agent_view' => 1, - 'agent_edit' => 1, - 'agent_disable' => 1, - 'alert_edit' => 1, - 'alert_management' => 1, - 'pandora_management' => 1, - 'db_management' => 1, - 'user_management' => 1, - 'report_view' => 1, - 'report_edit' => 1, - 'report_management' => 1, - 'event_view' => 1, - 'event_edit' => 1, - 'event_management' => 1, - 'map_view' => 1, - 'map_edit' => 1, - 'map_management' => 1, - 'vconsole_view' => 1, - 'vconsole_edit' => 1, - 'vconsole_management' => 1, - 'tags' => 1, + 'agent_view' => 1, + 'agent_edit' => 1, + 'agent_disable' => 1, + 'alert_edit' => 1, + 'alert_management' => 1, + 'pandora_management' => 1, + 'db_management' => 1, + 'user_management' => 1, + 'report_view' => 1, + 'report_edit' => 1, + 'report_management' => 1, + 'event_view' => 1, + 'event_edit' => 1, + 'event_management' => 1, + 'map_view' => 1, + 'map_edit' => 1, + 'map_management' => 1, + 'vconsole_view' => 1, + 'vconsole_edit' => 1, + 'vconsole_management' => 1, + 'tags' => 1, + 'network_config_view' => 1, + 'network_config_edit' => 1, + 'network_config_management' => 1, + ]; foreach ($acl_group_a['tags'] as $key => $value) { @@ -838,13 +842,14 @@ function users_has_profile_without_UM($id_user, $id_groups) } -function users_get_user_profile($id_user) +function users_get_user_profile($id_user, $limit='') { $sql = sprintf( "SELECT * FROM tusuario_perfil INNER JOIN tperfil ON tperfil.id_perfil = tusuario_perfil.id_perfil - WHERE tusuario_perfil.id_usuario like '%s'", - $id_user + WHERE tusuario_perfil.id_usuario like '%s' %s", + $id_user, + $limit ); $aux = db_get_all_rows_sql($sql); diff --git a/pandora_console/include/javascript/pandora.js b/pandora_console/include/javascript/pandora.js index 3f1ef17b4d..a4c0a46e84 100644 --- a/pandora_console/include/javascript/pandora.js +++ b/pandora_console/include/javascript/pandora.js @@ -196,6 +196,13 @@ function agent_changed_by_multiple_agents(event, id_agent, selected) { serialized = ""; } + var id_group = null; + if (typeof $("#filter_group") !== "undefined") { + try { + id_group = $("#filter_group").val(); + } catch (error) {} + } + $("#module") .prop("disabled", true) .empty() @@ -238,7 +245,8 @@ function agent_changed_by_multiple_agents(event, id_agent, selected) { selection_mode: selection_mode, serialized: serialized, id_server: id_server, - status_module: module_status + status_module: module_status, + id_group: id_group }, function(data) { $("#module").empty(); @@ -575,7 +583,8 @@ function module_changed_by_multiple_modules(event, id_module, selected) { status_module: status_module, "module_name[]": idModules, selection_mode: selection_mode, - tags: tags_selected + tags: tags_selected, + id_group: id_group }, function(data) { $("#agents").append( @@ -2175,3 +2184,19 @@ $.fn.filterByText = function(textbox) { }); }); }; + +function loadPasswordConfig(id, value) { + $.ajax({ + url: "ajax.php", + data: { + page: "include/ajax/config.ajax", + token_name: `${value}`, + no_boolean: 1 + }, + type: "GET", + dataType: "json", + success: function(data) { + $(`#${id}`).val(data); + } + }); +} diff --git a/pandora_console/include/javascript/pandora_dashboards.js b/pandora_console/include/javascript/pandora_dashboards.js index 63bdf36227..374af546de 100644 --- a/pandora_console/include/javascript/pandora_dashboards.js +++ b/pandora_console/include/javascript/pandora_dashboards.js @@ -1542,3 +1542,18 @@ function loadSliceWidget(settings) { } }); } + +// eslint-disable-next-line no-unused-vars +function showManualThresholds(element) { + $("#min_warning").val(null); + $("#max_warning").val(null); + $("#min_critical").val(null); + $("#max_critical").val(null); + if ($(element).is(":checked") === true) { + $(".dashboard-input-threshold-warning").removeClass("invisible_important"); + $(".dashboard-input-threshold-critical").removeClass("invisible_important"); + } else { + $(".dashboard-input-threshold-warning").addClass("invisible_important"); + $(".dashboard-input-threshold-critical").addClass("invisible_important"); + } +} diff --git a/pandora_console/include/javascript/pandora_events.js b/pandora_console/include/javascript/pandora_events.js index cd0796efee..df84985a37 100644 --- a/pandora_console/include/javascript/pandora_events.js +++ b/pandora_console/include/javascript/pandora_events.js @@ -85,29 +85,6 @@ function show_event_dialog(event, dialog_page) { $("#refrcounter").countdown("pause"); $("div.vc-countdown").countdown("pause"); - /* - switch (result) { - case "comment_ok": - $("#notification_comment_success").show(); - break; - case "comment_error": - $("#notification_comment_error").show(); - break; - case "status_ok": - $("#notification_status_success").show(); - break; - case "status_error": - $("#notification_status_error").show(); - break; - case "owner_ok": - $("#notification_owner_success").show(); - break; - case "owner_error": - $("#notification_owner_error").show(); - break; - } - */ - forced_title_callback(); }, "html" @@ -119,37 +96,152 @@ function show_event_dialog(event, dialog_page) { function execute_response(event_id, server_id) { var response_id = $("#select_custom_response option:selected").val(); - var response = get_response(response_id, server_id); - - // If cannot get response abort it - if (response == null) { - return; + var response_parameters_list = $('input[name^="values_params_"]'); + var response_parameters = []; + if (response_parameters_list.length > 0) { + response_parameters_list.each(function() { + var acum = { + name: $(this).attr("name"), + value: $(this).val() + }; + response_parameters.push(acum); + }); } - response["target"] = get_response_target(event_id, response_id, server_id); - response["event_id"] = event_id; - response["server_id"] = server_id; + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "get_response", value: 1 }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "server_id", value: server_id }); + params.push({ name: "event_id", value: event_id }); + params.push({ + name: "response_parameters", + value: JSON.stringify(response_parameters) + }); - if (response["type"] == "url" && response["new_window"] == 1) { - window.open(response["target"], "_blank"); - } else { - show_response_dialog(response_id, response); - } + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "json", + success: function(response) { + // If cannot get response abort it + if (response == null) { + return []; + } + + response["event_id"] = event_id; + response["server_id"] = server_id; + if (response["type"] == "url" && response["new_window"] == 1) { + window.open(response["target"], "_blank"); + } else { + show_response_dialog(response_id, response); + } + } + }); +} + +// Check the response type and open it in a modal dialog or new window +function execute_response_massive(events, response_id, response_parameters) { + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "get_response_massive", value: 1 }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "events", value: JSON.stringify(events) }); + params.push({ name: "response_parameters", value: response_parameters }); + + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "json", + success: function(data) { + // If cannot get response abort it + if (data == null) { + return []; + } + + $(".container-massive-events-response").empty(); + + // Convert to array. + var array_data = Object.entries(data.event_response_targets); + var total_count = array_data.length; + + // Each input checkeds. + array_data.forEach(function(element, index) { + var id = element[0]; + var target = element[1].target; + var meta = $("#hidden-meta").val(); + var event_id = id; + var server_id = 0; + if (meta != 0) { + var split_id = id.split("|"); + event_id = split_id[0]; + server_id = split_id[1]; + } + + var end = 0; + if (total_count - 1 === index) { + end = 1; + } + + var response = data.event_response; + response["event_id"] = event_id; + response["server_id"] = server_id; + response["target"] = target; + if (response["type"] == "url" && response["new_window"] == 1) { + window.open(response["target"], "_blank"); + } else { + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "get_row_response_action", value: 1 }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "server_id", value: response.server_id }); + params.push({ name: "end", value: end }); + params.push({ name: "response", value: JSON.stringify(response) }); + + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "html", + success: function(data) { + $(".container-massive-events-response").append(data); + response["event_id"] = event_id; + response["server_id"] = server_id; + response["target"] = target; + + var indexstr = event_id; + if (meta != 0) { + indexstr += "-" + server_id; + } + + perform_response( + btoa(JSON.stringify(response)), + response_id, + indexstr + ); + } + }); + } + }); + } + }); } //Show the modal window of an event response function show_response_dialog(response_id, response) { var params = []; - params.push("page=include/ajax/events"); - params.push("dialogue_event_response=1"); - params.push("massive=0"); - params.push("event_id=" + response["event_id"]); - params.push("target=" + encodeURIComponent(response["target"])); - params.push("response_id=" + response_id); - params.push("server_id=" + response["server_id"]); + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "dialogue_event_response", value: 1 }); + params.push({ name: "event_id", value: response.event_id }); + params.push({ name: "target", value: response.target }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "server_id", value: response.server_id }); + params.push({ name: "response", value: JSON.stringify(response) }); jQuery.ajax({ - data: params.join("&"), + data: params, type: "POST", url: $("#hidden-ajax_file").val(), dataType: "html", @@ -164,271 +256,49 @@ function show_response_dialog(response_id, response) { draggable: true, modal: false, open: function() { - perform_response(response, response_id); + perform_response(btoa(JSON.stringify(response)), response_id, ""); }, width: response["modal_width"], - height: response["modal_height"] + height: response["modal_height"], + buttons: [] }) .show(); } }); } -//Show the modal window of event responses when multiple events are selected -function show_massive_response_dialog( - response_id, - response, - out_iterator, - end -) { - var params = []; - params.push("page=include/ajax/events"); - params.push("dialogue_event_response=1"); - params.push("massive=1"); - params.push("end=" + end); - params.push("out_iterator=" + out_iterator); - params.push("event_id=" + response["event_id"]); - params.push("target=" + response["target"]); - params.push("response_id=" + response_id); - params.push("server_id=" + response["server_id"]); +// Perform a response and put the output into a div +function perform_response(response, response_id, index) { + $("#re_exec_command" + index).hide(); + $("#response_loading_command" + index).show(); + $("#response_out" + index).html(""); - jQuery.ajax({ - data: params.join("&"), - response_tg: response, - response_id: response_id, - out_iterator: out_iterator, - type: "POST", - url: $("#hidden-ajax_file").val(), - dataType: "html", - success: function(data) { - if (out_iterator === 0) $("#event_response_window").empty(); - - $("#event_response_window") - .hide() - .append(data) - .dialog({ - title: $("#select_custom_response option:selected").html(), - resizable: true, - draggable: true, - modal: false, - open: function() { - $("#response_loading_dialog").hide(); - $("#button-submit_event_response").show(); - }, - close: function() { - $("#checkbox-all_validate_box").prop("checked", false); - $(".chk_val").prop("checked", false); - }, - width: response["modal_width"], - height: response["modal_height"] - }) - .show(); - - perform_response_massive( - this.response_tg, - this.response_id, - this.out_iterator - ); - } - }); -} - -// Get an event response from db -function get_response(response_id, server_id) { - var response = ""; - - var params = []; - params.push("page=include/ajax/events"); - params.push("get_response=1"); - params.push("response_id=" + response_id); - params.push("server_id=" + server_id); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - async: false, - dataType: "json", - success: function(data) { - response = data; - } - }); - - return response; -} - -// Get an event response params from db -function get_response_params(response_id) { - var response_params; - - var params = []; - params.push("page=include/ajax/events"); - params.push("get_response_params=1"); - params.push("response_id=" + response_id); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - async: false, - dataType: "json", - success: function(data) { - response_params = data; - } - }); - - return response_params; -} - -// Get an event response description from db -function get_response_description(response_id) { - var response_description = ""; - - var params = []; - params.push("page=include/ajax/events"); - params.push("get_response_description=1"); - params.push("response_id=" + response_id); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - async: false, - dataType: "html", - success: function(data) { - response_description = data; - } - }); - - return response_description; -} - -function add_row_param(id_table, param) { - $("#" + id_table).append( - '' + - param + - '' - ); -} - -// Get an event response from db -function get_response_target( - event_id, - response_id, - server_id, - response_command -) { - var target = ""; - - // Replace the main macros - var params = []; - params.push("page=include/ajax/events"); - params.push("get_response_target=1"); - params.push("event_id=" + event_id); - params.push("response_id=" + response_id); - params.push("server_id=" + server_id); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - async: false, - dataType: "html", - success: function(data) { - target = data; - } - }); - - // Replace the custom params macros. - var response_params = get_response_params(response_id); - if (response_params.length > 1 || response_params[0] != "") { - for (var i = 0; i < response_params.length; i++) { - if (!response_command) { - var response_param = "_" + response_params[i] + "_"; - - if ( - response_params[i].startsWith("_") && - response_params[i].endsWith("_") - ) { - response_param = response_params[i]; - } - - target = target.replace( - response_param, - $("#" + response_params[i]).val() - ); - } else { - target = target.replace( - "_" + response_params[i] + "_", - response_command[response_params[i] + "-" + i] - ); - } - } + try { + response = JSON.parse(atob(response)); + } catch (e) { + console.error(e); + return; } - return target; -} - -// Perform a response and put the output into a div -function perform_response(response, response_id) { - $("#re_exec_command").hide(); - $("#response_loading_command").show(); - $("#response_out").html(""); - var params = []; - params.push("page=include/ajax/events"); - params.push("perform_event_response=1"); - params.push("target=" + encodeURIComponent(response["target"])); - params.push("response_id=" + response_id); - params.push("event_id=" + response["event_id"]); - params.push("server_id=" + response["server_id"]); + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "perform_event_response", value: 1 }); + params.push({ name: "target", value: response["target"] }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "event_id", value: response["event_id"] }); + params.push({ name: "server_id", value: response["server_id"] }); + params.push({ name: "response", value: JSON.stringify(response) }); jQuery.ajax({ - data: params.join("&"), + data: params, type: "POST", url: $("#hidden-ajax_file").val(), - async: true, dataType: "html", success: function(data) { var out = data.replace(/[\n|\r]/g, "
"); - $("#response_out").html(out); - $("#response_loading_command").hide(); - $("#re_exec_command").show(); - } - }); - - return false; -} - -// Perform a response and put the output into a div -function perform_response_massive(response, response_id, out_iterator) { - $("#re_exec_command").hide(); - $("#response_loading_command_" + out_iterator).show(); - $("#response_out_" + out_iterator).html(""); - - var params = []; - params.push("page=include/ajax/events"); - params.push("perform_event_response=1"); - params.push("target=" + response["target"]); - params.push("response_id=" + response_id); - params.push("event_id=" + response["event_id"]); - params.push("server_id=" + response["server_id"]); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - async: true, - dataType: "html", - success: function(data) { - var out = data.replace(/[\n|\r]/g, "
"); - $("#response_out_" + out_iterator).html(out); - $("#response_loading_command_" + out_iterator).hide(); - $("#re_exec_command_" + out_iterator).show(); + $("#response_out" + index).html(out); + $("#response_loading_command" + index).hide(); + $("#re_exec_command" + index).show(); } }); @@ -600,54 +470,6 @@ function event_comment(current_event) { return false; } -function show_event_response_command_dialog(id, response, total_checked) { - var params = []; - params.push("page=include/ajax/events"); - params.push("get_table_response_command=1"); - params.push("event_response_id=" + id); - - jQuery.ajax({ - data: params.join("&"), - type: "POST", - url: $("#hidden-ajax_file").val(), - dataType: "html", - success: function(data) { - $("#event_response_command_window") - .hide() - .empty() - .append(data) - .dialog({ - resizable: true, - draggable: true, - modal: false, - open: function() { - $("#response_loading_dialog").hide(); - $("#button-submit_event_response").show(); - }, - width: 600, - height: 300 - }) - .show(); - - $("#submit-enter_command").on("click", function(e) { - e.preventDefault(); - var response_command = []; - - $(".response_command_input").each(function() { - response_command[$(this).attr("name")] = $(this).val(); - }); - - check_massive_response_event( - id, - response, - total_checked, - response_command - ); - }); - } - }); -} - var processed = 0; function update_event(table, id_evento, type, event_rep, row, server_id) { var inputs = $("#events_form :input"); @@ -820,8 +642,13 @@ function execute_delete_event_reponse( // Imported from old files. function execute_event_response(event_list_btn) { + var response_id = $("select[name=response_id]").val(); + if (!isNaN(response_id)) { + table_info_response_event(response_id, 0, 0, true); + } + var message = - "

Are you sure?

"; + "

Are you sure?

"; confirmDialog({ title: "ATTENTION", message: message, @@ -833,8 +660,6 @@ function execute_event_response(event_list_btn) { $("#max_custom_event_resp_msg").hide(); $("#max_custom_selected").hide(); - var response_id = $("select[name=response_id]").val(); - var total_checked = $(".chk_val:checked").length; // Check select an event. @@ -844,58 +669,28 @@ function execute_event_response(event_list_btn) { } if (!isNaN(response_id)) { - // It is a custom response - var response = get_response(response_id); - - // If cannot get response abort it - if (response == null) { - return; + var response_parameters_list = $('input[name^="values_params_"]'); + var response_parameters = []; + if (response_parameters_list.length > 0) { + response_parameters_list.each(function() { + var acum = { + name: $(this).attr("name"), + value: $(this).val() + }; + response_parameters.push(acum); + }); } - // Limit number of events to apply custom responses - // due performance reasons. - if (total_checked > $("#max_execution_event_response").val()) { - $("#max_custom_event_resp_msg").show(); - return; - } - - var response_command = []; - $(".response_command_input").each(function() { - response_command[$(this).attr("name")] = $(this).val(); - }); + response_parameters = JSON.stringify(response_parameters); if (event_list_btn) { $("#button-submit_event_response").hide(function() { $("#response_loading_dialog").show(function() { - var check_params = get_response_params(response_id); - - if (check_params[0] !== "") { - show_event_response_command_dialog( - response_id, - response, - total_checked - ); - } else { - check_massive_response_event( - response_id, - response, - total_checked, - response_command - ); - } + show_response_dialog_massive(response_id, response_parameters); }); }); } else { - $("#button-btn_str").hide(function() { - $("#execute_again_loading").show(function() { - check_massive_response_event( - response_id, - response, - total_checked, - response_command - ); - }); - }); + check_execute_response_massive(response_id, response_parameters); } } else { // It is not a custom response @@ -912,7 +707,7 @@ function execute_event_response(event_list_btn) { } in_process_event( - "events", + "table_events", event_id, $(this).attr("event_rep"), this.parentElement.parentElement, @@ -932,7 +727,7 @@ function execute_event_response(event_list_btn) { } validate_event( - "events", + "table_events", event_id, $(this).attr("event_rep"), this.parentElement.parentElement, @@ -952,7 +747,7 @@ function execute_event_response(event_list_btn) { } execute_delete_event_reponse( - "events", + "table_events", event_id, $(this).attr("event_rep"), this.parentElement.parentElement, @@ -970,15 +765,63 @@ function execute_event_response(event_list_btn) { }); } -function check_massive_response_event( - response_id, - response, - total_checked, - response_command -) { - var counter = 0; - var end = 0; +function show_response_dialog_massive(response_id, response_parameters) { + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "get_response", value: 1 }); + params.push({ name: "response_id", value: response_id }); + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "json", + success: function(response) { + // If cannot get response abort it + if (response == null) { + return []; + } + + $("#event_response_window") + .hide() + .empty() + .append('
') + .dialog({ + title: $("#response_id option:selected").html(), + resizable: true, + draggable: true, + modal: false, + open: function() { + check_execute_response_massive(response_id, response_parameters); + }, + close: function() { + $("#checkbox-all_validate_box").prop("checked", false); + $(".chk_val").prop("checked", false); + $("#response_loading_dialog").hide(); + $("#button-submit_event_response").show(); + }, + buttons: [ + { + text: "Execute All", + id: "execute-again-all", + class: + "ui-widget ui-state-default ui-corner-all ui-button-text-only sub ok submit-next", + click: function() { + execute_event_response(false); + } + } + ], + width: response["modal_width"], + height: response["modal_height"] + }) + .show(); + } + }); +} + +function check_execute_response_massive(response_id, response_parameters) { + var events = []; + $(".container-massive-events-response").empty(); $(".chk_val:checked").each(function() { var event_id = $(this).val(); var meta = $("#hidden-meta").val(); @@ -987,23 +830,18 @@ function check_massive_response_event( var split_id = event_id.split("|"); event_id = split_id[0]; server_id = split_id[1]; + + if (events[server_id] === undefined) { + events[server_id] = []; + } + + events[server_id].push(event_id); + } else { + events.push(event_id); } - - response["target"] = get_response_target( - event_id, - response_id, - server_id, - response_command - ); - response["server_id"] = server_id; - response["event_id"] = event_id; - - if (total_checked - 1 === counter) end = 1; - - show_massive_response_dialog(response_id, response, counter, end); - - counter++; }); + + execute_response_massive(events, response_id, response_parameters); } function event_widget_options() { @@ -1287,3 +1125,43 @@ function check_event_sound(settings) { "json" ); } + +function table_info_response_event(response_id, event_id, server_id, massive) { + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "get_response", value: 1 }); + params.push({ name: "response_id", value: response_id }); + params.push({ name: "server_id", value: server_id }); + params.push({ name: "event_id", value: event_id }); + + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "json", + success: function(response) { + if (response) { + var params = []; + params.push({ name: "page", value: "include/ajax/events" }); + params.push({ name: "draw_row_response_info", value: 1 }); + params.push({ name: "massive", value: massive === true ? 1 : 0 }); + params.push({ name: "response", value: JSON.stringify(response) }); + + jQuery.ajax({ + data: params, + type: "POST", + url: $("#hidden-ajax_file").val(), + dataType: "html", + success: function(output) { + if (massive === true) { + $("#massive-parameters-response").append(output); + } else { + $(".params_rows").remove(); + $("#responses_table").append(output); + } + } + }); + } + } + }); +} diff --git a/pandora_console/include/javascript/pandora_ui.js b/pandora_console/include/javascript/pandora_ui.js index eeeb5fcfd5..ecb23827d9 100644 --- a/pandora_console/include/javascript/pandora_ui.js +++ b/pandora_console/include/javascript/pandora_ui.js @@ -740,3 +740,26 @@ function reveal_password(name) { revealElement.attr("src", imagesPath + "eye_show.png"); } } + +/** + * Returns html img group icon. + * @param {int} $id_group + */ +function getGroupIcon(id_group, img_container) { + $.ajax({ + type: "POST", + url: "ajax.php", + dataType: "json", + data: { + page: "godmode/groups/group_list", + get_group_json: 1, + id_group: id_group + }, + success: function(data) { + img_container.attr("src", "images/groups_small/" + data["icon"] + ".png"); + }, + error: function() { + img_container.attr("src", ""); + } + }); +} diff --git a/pandora_console/include/javascript/tree/TreeController.js b/pandora_console/include/javascript/tree/TreeController.js index 073a862c4c..f3dc4ad16a 100644 --- a/pandora_console/include/javascript/tree/TreeController.js +++ b/pandora_console/include/javascript/tree/TreeController.js @@ -858,11 +858,12 @@ var TreeController = { $content.append($statusImage); } var image_tooltip = - '' +
+                ' '; @@ -883,7 +884,6 @@ var TreeController = { window.location.href = element.serviceDetail; }) .css("cursor", "pointer"); - $content.append($serviceDetailImage); $content.append(" " + image_tooltip); diff --git a/pandora_console/include/lib/Core/Config.php b/pandora_console/include/lib/Core/Config.php index dbed566598..656d68f9f2 100644 --- a/pandora_console/include/lib/Core/Config.php +++ b/pandora_console/include/lib/Core/Config.php @@ -69,7 +69,7 @@ final class Config $link->options(MYSQLI_OPT_CONNECT_TIMEOUT, 2); $rc = mysqli_real_connect( $link, - $$config['history_db_host'], + $config['history_db_host'], $config['history_db_user'], io_output_password($config['history_db_pass']), $config['history_db_name'], @@ -90,29 +90,31 @@ final class Config } ob_get_clean(); + } - if ($config['history_db_connection'] !== false) { - $data = \db_get_all_rows_sql( - 'SELECT * FROM `tconfig`', - false, - false, - $config['history_db_connection'] - ); - } - - if (is_array($data) !== true) { - return []; - } - - self::$settings = array_reduce( - $data, - function ($carry, $item) { - $carry[$item['token']] = $item['value']; - return $carry; - }, - [] + if (isset($config['history_db_connection']) === true + && $config['history_db_connection'] !== false + ) { + $data = \db_get_all_rows_sql( + 'SELECT * FROM `tconfig`', + false, + false, + $config['history_db_connection'] ); } + + if (is_array($data) !== true) { + return []; + } + + self::$settings = array_reduce( + $data, + function ($carry, $item) { + $carry[$item['token']] = $item['value']; + return $carry; + }, + [] + ); } diff --git a/pandora_console/include/lib/Dashboard/Widget.php b/pandora_console/include/lib/Dashboard/Widget.php index cbb4a7ccfe..de5727a56f 100644 --- a/pandora_console/include/lib/Dashboard/Widget.php +++ b/pandora_console/include/lib/Dashboard/Widget.php @@ -416,6 +416,7 @@ class Widget $className .= '\OsQuickReportWidget'; break; + case 'GroupedMeterGraphs': case 'ColorModuleTabs': case 'BlockHistogram': $className .= '\\'.$name; diff --git a/pandora_console/include/lib/Dashboard/Widgets/GroupedMeterGraphs.php b/pandora_console/include/lib/Dashboard/Widgets/GroupedMeterGraphs.php new file mode 100644 index 0000000000..2eed27df11 --- /dev/null +++ b/pandora_console/include/lib/Dashboard/Widgets/GroupedMeterGraphs.php @@ -0,0 +1,1058 @@ +width = $width; + + // Height. + $this->height = $height; + + // Grid Width. + $this->gridWidth = $gridWidth; + + // Cell Id. + $this->cellId = $cellId; + + // Options. + $this->values = $this->decoders($this->getOptionsWidget()); + + // Positions. + $this->position = $this->getPositionWidget(); + + // Page. + $this->page = basename(__FILE__); + + // ClassName. + $class = new \ReflectionClass($this); + $this->className = $class->getShortName(); + + // Title. + $this->title = __('Color tabs modules'); + + // Name. + if (empty($this->name) === true) { + $this->name = 'single_graph'; + } + + // This forces at least a first configuration. + $this->configurationRequired = false; + if (empty($this->values['moduleGroupedMeterGraphs']) === true) { + $this->configurationRequired = true; + } + + $this->overflow_scrollbars = false; + } + + + /** + * Decoders hack for retrocompability. + * + * @param array $decoder Values. + * + * @return array Returns the values ​​with the correct key. + */ + public function decoders(array $decoder): array + { + $values = []; + // Retrieve global - common inputs. + $values = parent::decoders($decoder); + + $values['agentsGroupedMeterGraphs'] = []; + if (isset($decoder['agentsGroupedMeterGraphs']) === true) { + if (isset($decoder['agentsGroupedMeterGraphs'][0]) === true + && empty($decoder['agentsGroupedMeterGraphs']) === false + ) { + $values['agentsGroupedMeterGraphs'] = explode( + ',', + $decoder['agentsGroupedMeterGraphs'][0] + ); + } + } + + if (isset($decoder['selectionGroupedMeterGraphs']) === true) { + $values['selectionGroupedMeterGraphs'] = $decoder['selectionGroupedMeterGraphs']; + } + + $values['moduleGroupedMeterGraphs'] = []; + if (isset($decoder['moduleGroupedMeterGraphs']) === true) { + if (empty($decoder['moduleGroupedMeterGraphs']) === false) { + $values['moduleGroupedMeterGraphs'] = $decoder['moduleGroupedMeterGraphs']; + } + } + + if (isset($decoder['formatData']) === true) { + $values['formatData'] = $decoder['formatData']; + } + + if (isset($decoder['manualThresholds']) === true) { + $values['manualThresholds'] = $decoder['manualThresholds']; + } + + $values['label'] = 'module'; + if (isset($decoder['label']) === true) { + $values['label'] = $decoder['label']; + } + + $values['min_value'] = null; + if (isset($decoder['min_value']) === true) { + $values['min_value'] = $decoder['min_value']; + } + + $values['max_value'] = null; + if (isset($decoder['max_value']) === true) { + $values['max_value'] = $decoder['max_value']; + } + + $values['min_critical'] = null; + if (isset($decoder['min_critical']) === true) { + $values['min_critical'] = $decoder['min_critical']; + } + + $values['max_critical'] = null; + if (isset($decoder['max_critical']) === true) { + $values['max_critical'] = $decoder['max_critical']; + } + + $values['min_warning'] = null; + if (isset($decoder['min_warning']) === true) { + $values['min_warning'] = $decoder['min_warning']; + } + + $values['max_warning'] = null; + if (isset($decoder['max_warning']) === true) { + $values['max_warning'] = $decoder['max_warning']; + } + + if (isset($decoder['fontColor']) === true) { + $values['fontColor'] = $decoder['fontColor']; + } + + return $values; + } + + + /** + * Generates inputs for form (specific). + * + * @return array Of inputs. + * + * @throws Exception On error. + */ + public function getFormInputs(): array + { + $values = $this->values; + + // Retrieve global - common inputs. + $inputs = parent::getFormInputs(); + + $blocks = [ + 'row1', + 'row2', + ]; + + $inputs['blocks'] = $blocks; + + foreach ($inputs as $kInput => $vInput) { + $inputs['inputs']['row1'][] = $vInput; + } + + if (empty($values['fontColor']) === true) { + $values['fontColor'] = '#2c3e50'; + } + + $inputs['inputs']['row1'][] = [ + 'label' => __('Font color'), + 'arguments' => [ + 'wrapper' => 'div', + 'name' => 'fontColor', + 'type' => 'color', + 'value' => $values['fontColor'], + 'return' => true, + ], + ]; + + // Format Data. + $inputs['inputs']['row1'][] = [ + 'label' => __('Format Data'), + 'arguments' => [ + 'name' => 'formatData', + 'id' => 'formatData', + 'type' => 'switch', + 'value' => $values['formatData'], + ], + ]; + + $inputs['inputs']['row1'][] = [ + 'class' => 'dashboard-input-threshold', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Values'), + 'arguments' => [], + ], + [ + 'label' => __('Min'), + 'arguments' => [ + 'name' => 'min_value', + 'id' => 'min_value', + 'type' => 'number', + 'value' => $values['min_value'], + ], + ], + [ + 'label' => __('Max'), + 'arguments' => [ + 'name' => 'max_value', + 'id' => 'max_value', + 'type' => 'number', + 'value' => $values['max_value'], + ], + ], + ], + + ]; + + // Format Data. + $inputs['inputs']['row1'][] = [ + 'label' => __('Manual thresholds'), + 'arguments' => [ + 'name' => 'manualThresholds', + 'id' => 'manualThresholds', + 'type' => 'switch', + 'value' => $values['manualThresholds'], + 'onchange' => 'showManualThresholds(this)', + ], + ]; + + $class_invisible = ''; + if ((bool) $values['manualThresholds'] !== true) { + $class_invisible = 'invisible_important'; + } + + $inputs['inputs']['row1'][] = [ + 'class' => 'dashboard-input-threshold dashboard-input-threshold-warning '.$class_invisible, + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Warning threshold'), + 'arguments' => [], + ], + [ + 'label' => __('Min'), + 'arguments' => [ + 'name' => 'min_warning', + 'id' => 'min_warning', + 'type' => 'number', + 'value' => $values['min_warning'], + ], + ], + [ + 'label' => __('Max'), + 'arguments' => [ + 'name' => 'max_warning', + 'id' => 'max_warning', + 'type' => 'number', + 'value' => $values['max_warning'], + ], + ], + ], + ]; + + $inputs['inputs']['row1'][] = [ + 'class' => 'dashboard-input-threshold dashboard-input-threshold-critical '.$class_invisible, + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Critical threshold'), + 'arguments' => [], + ], + [ + 'label' => __('Min'), + 'arguments' => [ + 'name' => 'min_critical', + 'id' => 'min_critical', + 'type' => 'number', + 'value' => $values['min_critical'], + ], + ], + [ + 'label' => __('Max'), + 'arguments' => [ + 'name' => 'max_critical', + 'id' => 'max_critical', + 'type' => 'number', + 'value' => $values['max_critical'], + ], + ], + ], + + ]; + + // Type Label. + $fields = [ + 'module' => __('Module'), + 'agent' => __('Agent'), + 'agent_module' => __('Agent / module'), + ]; + + $inputs['inputs']['row2'][] = [ + 'label' => __('Label'), + 'arguments' => [ + 'type' => 'select', + 'fields' => $fields, + 'name' => 'label', + 'selected' => $values['label'], + 'return' => true, + ], + ]; + + $inputs['inputs']['row2'][] = [ + 'arguments' => [ + 'type' => 'select_multiple_modules_filtered_select2', + 'agent_values' => agents_get_agents_selected(0), + 'agent_name' => 'agentsGroupedMeterGraphs[]', + 'agent_ids' => $values['agentsGroupedMeterGraphs'], + 'selectionModules' => $values['selectionGroupedMeterGraphs'], + 'selectionModulesNameId' => 'selectionGroupedMeterGraphs', + 'modules_ids' => $values['moduleGroupedMeterGraphs'], + 'modules_name' => 'moduleGroupedMeterGraphs[]', + 'notStringModules' => true, + ], + ]; + + return $inputs; + } + + + /** + * Get Post for widget. + * + * @return array + */ + public function getPost():array + { + // Retrieve global - common inputs. + $values = parent::getPost(); + + $values['agentsGroupedMeterGraphs'] = \get_parameter( + 'agentsGroupedMeterGraphs', + [] + ); + $values['selectionGroupedMeterGraphs'] = \get_parameter( + 'selectionGroupedMeterGraphs', + 0 + ); + + $values['moduleGroupedMeterGraphs'] = \get_parameter( + 'moduleGroupedMeterGraphs' + ); + + $agColor = []; + if (isset($values['agentsGroupedMeterGraphs'][0]) === true + && empty($values['agentsGroupedMeterGraphs'][0]) === false + ) { + $agColor = explode(',', $values['agentsGroupedMeterGraphs'][0]); + } + + $agModule = []; + if (isset($values['moduleGroupedMeterGraphs'][0]) === true + && empty($values['moduleGroupedMeterGraphs'][0]) === false + ) { + $agModule = explode(',', $values['moduleGroupedMeterGraphs'][0]); + } + + $values['moduleGroupedMeterGraphs'] = get_same_modules_all( + $agColor, + $agModule + ); + + $values['formatData'] = \get_parameter_switch('formatData', 0); + + $values['fontColor'] = \get_parameter('fontColor', '#2c3e50'); + + $values['label'] = \get_parameter('label', 'module'); + + $values['min_value'] = \get_parameter('min_value', null); + $values['max_value'] = \get_parameter('max_value', null); + + $values['manualThresholds'] = \get_parameter_switch('manualThresholds', 0); + $values['min_critical'] = \get_parameter('min_critical', null); + $values['max_critical'] = \get_parameter('max_critical', null); + $values['min_warning'] = \get_parameter('min_warning', null); + $values['max_warning'] = \get_parameter('max_warning', null); + + return $values; + } + + + /** + * Draw widget. + * + * @return string; + */ + public function load() + { + $this->size = parent::getSize(); + $this->boxNumber = ceil(($this->size['width'] * 0.65) / self::RATIO_WITH_BOX); + + $output = ''; + if (is_metaconsole() === true) { + $modules_nodes = array_reduce( + $this->values['moduleGroupedMeterGraphs'], + function ($carry, $item) { + $explode = explode('|', $item); + $carry[$explode[0]][] = $explode[1]; + return $carry; + }, + [] + ); + + $modules = []; + foreach ($modules_nodes as $n => $mod) { + try { + $node = new Node((int) $n); + $node->connect(); + $node_mods = $this->getInfoModules($mod); + if (empty($node_mods) === false) { + foreach ($node_mods as $value) { + $value['id_node'] = $n; + $value['server_name'] = $node->toArray()['server_name']; + $modules[] = $value; + } + } + + $node->disconnect(); + } catch (\Exception $e) { + // Unexistent agent. + $node->disconnect(); + } + } + } else { + $modules = $this->getInfoModules( + $this->values['moduleGroupedMeterGraphs'] + ); + } + + if ($modules !== false + && empty($modules) === false + && is_array($modules) === true + ) { + if (count($modules) > self::MAX_MODULES) { + $output .= '
'; + $output .= \ui_print_info_message( + __( + 'The maximum number of modules to display is %d, please reconfigure the widget.', + self::MAX_MODULES + ), + '', + true + ); + $output .= '
'; + return $output; + } + + $max = null; + $min = null; + // Dinamic treshold. + if ($this->values['min_critical'] !== null + || $this->values['max_critical'] !== null + || $this->values['min_warning'] !== null + || $this->values['max_warning'] !== null + ) { + if ($this->values['max_value'] === null || $this->values['min_value'] === null) { + $tresholdData = [ + ($this->values['min_critical'] ?? 0), + ($this->values['max_critical'] ?? 0), + ($this->values['min_warning'] ?? 0), + ($this->values['max_warning'] ?? 0), + ]; + + $moduleData = array_map( + function ($module) { + return ($module['data'] ?? 0); + }, + $modules + ); + } + + if ($this->values['max_value'] === null) { + $max = max( + array_merge( + $moduleData, + $tresholdData + ) + ); + } else { + $max = $this->values['max_value']; + } + + // Increases max. + if ($this->values['max_critical'] === null && $this->values['max_value'] === null) { + $max_increase = ($max * self::MAX_INCREASE); + $max = ($max + $max_increase); + } + + if ($this->values['min_value'] === null) { + $min = min( + array_merge( + $moduleData, + $tresholdData + ) + ); + } else { + $min = $this->values['min_value']; + } + + $tresholds_array = [ + 'min_critical' => $this->values['min_critical'], + 'max_critical' => $this->values['max_critical'], + 'min_warning' => $this->values['min_warning'], + 'max_warning' => $this->values['max_warning'], + ]; + + $this->thresholds = $this->calculateThreshold($max, $min, $tresholds_array); + } + + $style = 'color:'.$this->values['fontColor'].';'; + $output .= '
'; + foreach ($modules as $module) { + $output .= $this->drawRowModule( + $module, + $max, + $min + ); + } + + $output .= '
'; + } else { + $output .= '
'; + $output .= \ui_print_info_message( + __('Not found modules'), + '', + true + ); + $output .= '
'; + } + + return $output; + } + + + /** + * Get info modules. + * + * @param array $modules Modules. + * + * @return array Data. + */ + private function getInfoModules(array $modules): array + { + $where = sprintf( + 'tagente_modulo.id_agente_modulo IN (%s) + AND tagente_modulo.delete_pending = 0', + implode(',', $modules) + ); + + $sql = sprintf( + 'SELECT tagente_modulo.id_agente_modulo AS `id`, + tagente_modulo.nombre AS `name`, + tagente_modulo.unit AS `unit`, + tagente_modulo.min_warning AS w_min, + tagente_modulo.max_warning AS w_max, + tagente_modulo.str_warning AS w_str, + tagente_modulo.min_critical AS c_min, + tagente_modulo.max_critical AS c_max, + tagente_modulo.str_critical AS c_str, + tagente_modulo.id_tipo_modulo AS type_module, + tagente_estado.datos AS `data`, + tagente_estado.timestamp AS `timestamp`, + tagente_estado.estado AS `status`, + tagente.alias + FROM tagente_modulo + LEFT JOIN tagente_estado + ON tagente_modulo.id_agente_modulo = tagente_estado.id_agente_modulo + LEFT JOIN tagente + ON tagente_modulo.id_agente = tagente.id_agente + WHERE %s', + $where + ); + + $modules = db_get_all_rows_sql($sql); + + if ($modules === false) { + $modules = []; + } + + return $modules; + } + + + /** + * Draw info module. + * + * @param array $data Data module. + * @param null|float $max Value max. + * @param null|float $min Value min. + * + * @return string + */ + private function drawRowModule( + array $data, + ?float $max, + ?float $min + ):string { + global $config; + + // Dinamic. + if ($max === null && $min === null) { + $all_values_module = [ + ($data['w_min'] ?? 0), + ($data['w_max'] ?? 0), + ($data['c_min'] ?? 0), + ($data['c_max'] ?? 0), + ($data['data'] ?? 0), + ]; + + if ($this->values['max_value'] === null) { + $max = max($all_values_module); + } else { + $max = $this->values['max_value']; + } + + // Increases max. + if (empty($data['c_max']) === true + && $this->values['max_value'] === null + ) { + $max_increase = ($max * self::MAX_INCREASE); + $max = ($max + $max_increase); + } + + $min = 0; + if ($this->values['min_value'] !== null) { + $min = $this->values['min_value']; + } + + $thresholds_array = [ + 'min_critical' => (empty($data['c_min']) === true) ? null : $data['c_min'], + 'max_critical' => (empty($data['c_max']) === true) ? null : $data['c_max'], + 'min_warning' => (empty($data['w_min']) === true) ? null : $data['w_min'], + 'max_warning' => (empty($data['w_max']) === true) ? null : $data['w_max'], + ]; + + $this->thresholds = $this->calculateThreshold( + $max, + $min, + $thresholds_array + ); + } + + $module_data = $this->getBoxPercentageMaths($max, $min, (float) $data['data']); + + $output = ''; + $output .= '
'; + + // Module name. + $name = ''; + switch ($this->values['label']) { + case 'agent': + $name = $data['alias']; + break; + + case 'agent_module': + $name = $data['alias'].' / '.$data['name']; + break; + + default: + case 'module': + $name = $data['name']; + break; + } + + $output .= '
'; + $output .= $name; + $output .= '
'; + + // Graphs. + $output .= '
'; + for ($i = 0; $i < $this->boxNumber; $i++) { + $class = 'meter-graph-'; + $class .= $this->getThresholdStatus($i); + + if ($module_data > $i) { + $class .= ' meter-graph-opacity'; + } + + $output .= '
'; + $output .= '
'; + } + + $output .= '
'; + + // Data. + $class = 'container-info-module-meter-data'; + $class .= ' meter-data-'; + $class .= $this->getThresholdStatus($module_data); + + $result_data = ''; + if ($data['data'] !== null && $data['data'] !== '') { + if (isset($this->values['formatData']) === true + && (bool) $this->values['formatData'] === true + ) { + $result_data .= format_for_graph( + $data['data'], + $config['graph_precision'] + ); + } else { + $result_data .= sla_truncate( + $data['data'], + $config['graph_precision'] + ); + } + + $result_data .= ' '.$data['unit']; + } else { + $result_data .= '--'; + } + + $output .= '
'; + $output .= $result_data; + $output .= '
'; + + $output .= '
'; + + return $output; + } + + + /** + * Get status. + * + * @return array + */ + private static function getStatuses() + { + return [ + self::STATUS_CRITICAL, + self::STATUS_WARNING, + self::STATUS_NORMAL, + ]; + } + + + /** + * Get tresholds. + * + * @param float $max Value max. + * @param float $min Value min. + * @param array $thresholds_array Array thresholds. + * + * @return array Array threshold. + */ + private function calculateThreshold(float $max, float $min, array $thresholds_array) + { + $nMax = null; + if ($thresholds_array['min_warning'] !== null) { + $nMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_warning']); + } + + $wMin = null; + if ($thresholds_array['min_warning'] !== null) { + $wMin = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_warning']); + } + + $wMax = null; + if ($thresholds_array['max_warning'] !== null) { + $wMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['max_warning']); + } + + $cMin = null; + if ($thresholds_array['min_critical'] !== null) { + $cMin = $this->getBoxPercentageMaths($max, $min, $thresholds_array['min_critical']); + } + + $cMax = null; + if ($thresholds_array['max_critical'] !== null) { + $cMax = $this->getBoxPercentageMaths($max, $min, $thresholds_array['max_critical']); + } + + $thresholds = [ + 'normal' => [ + 'min' => $this->getBoxPercentageMaths($max, $min, $min), + 'max' => $nMax, + ], + 'warning' => [ + 'min' => $wMin, + 'max' => $wMax, + ], + 'critical' => [ + 'min' => $cMin, + 'max' => $cMax, + ], + ]; + + return $thresholds; + } + + + /** + * Get porcentage. + * + * @param float $max Maximum. + * @param float $min Minimum. + * @param float $value Value. + * + * @return float + */ + private function getBoxPercentageMaths( + float $max, + float $min, + float $value + ):float { + if ($min === 0.00 && $max === 0.00) { + return 0; + } + + return (((($value - $min) / ($max - $min))) * $this->boxNumber); + } + + + /** + * Get status compare tresholds. + * + * @param float $value Value to compare. + * + * @return string + */ + private function getThresholdStatus( + float $value + ) { + foreach (self::getStatuses() as $status) { + if ($this->thresholds[$status]['min'] === null + && $this->thresholds[$status]['max'] === null + ) { + continue; + } + + if (($this->thresholds[$status]['min'] === null + && $this->thresholds[$status]['max'] >= $value) + || ($this->thresholds[$status]['max'] === null + && $this->thresholds[$status]['min'] <= $value) + || ($this->thresholds[$status]['min'] <= $value + && $this->thresholds[$status]['max'] >= $value) + ) { + return $status; + } + } + + return self::STATUS_NORMAL; + } + + + /** + * Get description. + * + * @return string. + */ + public static function getDescription() + { + return __('Grouped meter graphs'); + } + + + /** + * Get Name. + * + * @return string. + */ + public static function getName() + { + return 'GroupedMeterGraphs'; + } + + + /** + * Get size Modal Configuration. + * + * @return array + */ + public function getSizeModalConfiguration(): array + { + $size = [ + 'width' => (is_metaconsole() === true) ? 1000 : 900, + 'height' => 550, + ]; + + return $size; + } + + +} diff --git a/pandora_console/include/lib/Dashboard/Widgets/agent_module.php b/pandora_console/include/lib/Dashboard/Widgets/agent_module.php index d4eb582cfc..fbc4165b4d 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/agent_module.php +++ b/pandora_console/include/lib/Dashboard/Widgets/agent_module.php @@ -710,9 +710,13 @@ class AgentModuleWidget extends Widget if (empty($allModules) === false) { if (is_metaconsole() === true && $this->values['mShowCommonModules'] !== 'on') { - $modules = $agent->searchModules( - ['nombre' => array_keys($reduceAllModules['modules_selected'][$tserver])] - ); + if (isset($reduceAllModules['modules_selected'][$tserver]) === true) { + $modules = $agent->searchModules( + ['nombre' => array_keys($reduceAllModules['modules_selected'][$tserver])] + ); + } else { + $modules = null; + } } else { $modules = $agent->searchModules( ['nombre' => array_keys($allModules)] diff --git a/pandora_console/include/lib/Dashboard/Widgets/service_map.php b/pandora_console/include/lib/Dashboard/Widgets/service_map.php index 0fa8d13f10..9dfe181fd8 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/service_map.php +++ b/pandora_console/include/lib/Dashboard/Widgets/service_map.php @@ -328,7 +328,7 @@ class ServiceMapWidget extends Widget ]; $inputs[] = [ - 'label' => __('Enable sunburst'), + 'label' => __('Show sunburst by default'), 'arguments' => [ 'type' => 'switch', 'name' => 'sunburst', diff --git a/pandora_console/include/lib/User.php b/pandora_console/include/lib/User.php index ce03e31a03..227bb77c91 100644 --- a/pandora_console/include/lib/User.php +++ b/pandora_console/include/lib/User.php @@ -128,7 +128,7 @@ class User implements PublicLogin { $user = new self($data); - if ($user === null) { + if ($user->idUser === null) { return false; } @@ -188,6 +188,14 @@ class User implements PublicLogin $config['public_access'] = false; } + if (empty($other_secret) === true) { + $auth_token_secret = db_get_value('auth_token_secret', 'tusuario', 'id_user', $config['id_user']); + + if (empty($auth_token_secret) === false) { + $other_secret = $auth_token_secret; + } + } + // Build a hash to check. $hashCheck = self::generatePublicHash($other_secret); if ($hashCheck === $hash) { diff --git a/pandora_console/include/rest-api/index.php b/pandora_console/include/rest-api/index.php index 8db1b40c2f..dee51a9bc7 100644 --- a/pandora_console/include/rest-api/index.php +++ b/pandora_console/include/rest-api/index.php @@ -66,7 +66,19 @@ if ($doLogin === true) { ] ) === true ) { - echo json_encode(['auth_hash' => User::generatePublicHash()]); + $newGeneratedSecret = bin2hex(openssl_random_pseudo_bytes(15)); + + $res_update = update_user( + $id_user, + ['auth_token_secret' => $newGeneratedSecret] + ); + + if ($res_update === false) { + http_response_code(404); + return; + } + + echo json_encode(['auth_hash' => User::generatePublicHash($newGeneratedSecret)]); } else { db_pandora_audit( AUDIT_LOG_ACL_VIOLATION, diff --git a/pandora_console/include/styles/dashboards.css b/pandora_console/include/styles/dashboards.css index e8ab6204d9..64c6fbe4b4 100644 --- a/pandora_console/include/styles/dashboards.css +++ b/pandora_console/include/styles/dashboards.css @@ -677,6 +677,128 @@ form.modal-dashboard text-align: initial; } +.container-grouped-meter { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 98%; + margin-top: 10px; +} +.container-grouped-meter .container-info-module-meter { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + width: 100%; + height: 30px; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-title { + flex: 1 1 20%; + font-size: 100%; + font-weight: bolder; + text-align: right; + padding-right: 10px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs { + flex: 1 1 65%; + display: flex; + flex-direction: row; + justify-content: space-around; + align-items: center; + height: 100%; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs + div { + border-radius: 2px; + width: 17px; + height: 90%; + opacity: 0.4; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs + div.meter-graph-critical { + background-color: #e63c52; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs + div.meter-graph-warning { + background-color: #f3b200; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs + div.meter-graph-normal { + background-color: #82b92e; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-graphs + div.meter-graph-opacity { + opacity: 1; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-data { + flex: 1 1 15%; + font-size: 150%; + font-weight: bolder; + text-align: right; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-data.meter-data-critical { + color: #e63c52; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-data.meter-data-warning { + color: #f3b200; +} + +.container-grouped-meter + .container-info-module-meter + .container-info-module-meter-data.meter-data-normal { + color: #82b92e; +} + +.dashboard-input-threshold { + align-items: center; + justify-content: space-between; +} + +.dashboard-input-threshold input { + max-width: 20% !important; +} + +.dashboard-input-threshold label:not(:first-child) { + flex: 0 !important; +} + .content-widget .dataTables_wrapper { width: 98%; margin-top: 5px; diff --git a/pandora_console/include/styles/events.css b/pandora_console/include/styles/events.css index 2cb7d3a481..32317e3e4c 100644 --- a/pandora_console/include/styles/events.css +++ b/pandora_console/include/styles/events.css @@ -396,3 +396,59 @@ div.multi-response-buttons { .white_table_graph_header { align-items: center; } + +.container-massive-events-response { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; +} + +.container-massive-events-response-cell { + margin-bottom: 10px; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-content: flex-start; +} + +.container-massive-events-response-command > span { + font-style: italic; +} + +.container-massive-events-response-output { + /*border: 2px dashed #ddd;*/ + /*padding: 10px;*/ + margin: 10px; +} + +.container-massive-events-response-execute { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; +} + +#massive-parameters-response { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#massive-parameters-response > div { + width: 80%; +} + +#massive-parameters-response > div h5 { + text-align: center; +} + +#massive-parameters-response > div div { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin-bottom: 5px; +} diff --git a/pandora_console/include/styles/omnishell.css b/pandora_console/include/styles/omnishell.css index a958eb630a..16b5fdd50a 100644 --- a/pandora_console/include/styles/omnishell.css +++ b/pandora_console/include/styles/omnishell.css @@ -398,7 +398,6 @@ li > input[type="email"], border: none; border-radius: 0; border-bottom: 1px solid #ccc; - font-weight: lighter; padding: 0px 0px 2px 0px; box-sizing: border-box; margin-bottom: 4px; diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index eeff4d2fce..13e617f877 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -9119,3 +9119,37 @@ div#err_msg_centralised { margin-right: -110px; margin-top: 13px; } + +.tag-editor { + padding: 0.5em !important; +} + +.tag-editor div { + float: right !important; +} + +.tag-editor .tag-editor-tag { + padding: 5px !important; + color: #fff !important; + background: #82b92e !important; + border-radius: 0 2px 2px 0 !important; +} + +.tag-editor .tag-editor-delete { + padding: 5px !important; + line-height: 16px !important; + background: #82b92e !important; + border-radius: 2px 0 0 2px !important; +} + +.tag-editor .tag-editor-delete i { + line-height: 16pt !important; +} + +.tag-editor .tag-editor-delete i:before { + color: #fff !important; +} + +.tag-editor .tag-editor-delete:hover i:before { + color: #ccc !important; +} diff --git a/pandora_console/install.php b/pandora_console/install.php index d7d1442226..74dad39609 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -129,7 +129,7 @@
'.__('No').''; } else { @@ -1068,7 +1068,7 @@ class Events $filters['id_agent'] = $this->id_agent; } - $filters['group_rep'] = 1; + $filters['group_rep'] = EVENT_GROUP_REP_EVENTS; if (isset($this->limit) === true && $this->limit !== -1 diff --git a/pandora_console/operation/agentes/estado_generalagente.php b/pandora_console/operation/agentes/estado_generalagente.php index 42d325e7f0..91714803f9 100755 --- a/pandora_console/operation/agentes/estado_generalagente.php +++ b/pandora_console/operation/agentes/estado_generalagente.php @@ -564,7 +564,10 @@ for ($i = 0; $i < $custom_fields_count; $i++) { $columns = array_merge($first_column, $second_column); } else { $columns = $first_column; - $filas = count($table_data->data); + if ($table_data->data !== null) { + $filas = count($table_data->data); + } + $table_data->colspan[$filas][1] = 3; } diff --git a/pandora_console/operation/agentes/ver_agente.php b/pandora_console/operation/agentes/ver_agente.php index d3797d127b..e2616b8d08 100644 --- a/pandora_console/operation/agentes/ver_agente.php +++ b/pandora_console/operation/agentes/ver_agente.php @@ -223,7 +223,7 @@ if (is_ajax()) { $id_agents, $selection, $select_mode, - true + (bool) !$select_mode ); // Clean double safe input. @@ -480,6 +480,7 @@ if (is_ajax()) { $serialized = get_parameter('serialized', ''); $id_server = (int) get_parameter('id_server', 0); $status_modulo = (int) get_parameter('status_module', -1); + $id_group_selected = (int) get_parameter('id_group', 0); $metaconsole_server_name = null; if (!empty($id_server)) { $metaconsole_server_name = db_get_value( @@ -707,14 +708,18 @@ if (is_ajax()) { // Get all user's groups. $id_group = array_keys(users_get_groups($config['id_user'])); - if (is_array($id_group)) { + if (is_array($id_group) && empty($id_group_selected) === true) { $id_group = implode(',', $id_group); + } else { + if (in_array($id_group_selected, $id_group) === true) { + $id_group = $id_group_selected; + } } $where_tags .= ' AND tagente.id_grupo IN ('.$id_group.')'; if ($selection_mode == 'common') { - $sql_agent_total = 'SELECT count(*) FROM tagente WHERE disabled=0'; + $sql_agent_total = 'SELECT count(*) FROM tagente WHERE disabled=0'.$where_tags; $agent_total = db_get_value_sql($sql_agent_total); $sql = sprintf( "SELECT t1.nombre, t1.id_agente_modulo FROM tagente_modulo t1 diff --git a/pandora_console/operation/events/events.php b/pandora_console/operation/events/events.php index e289632aad..e95f16b355 100644 --- a/pandora_console/operation/events/events.php +++ b/pandora_console/operation/events/events.php @@ -84,7 +84,7 @@ ui_require_javascript_file('pandora_events'); $default_filter = [ 'status' => EVENT_NO_VALIDATED, 'event_view_hr' => $config['event_view_hr'], - 'group_rep' => 1, + 'group_rep' => EVENT_GROUP_REP_EVENTS, 'tag_with' => [], 'tag_without' => [], 'history' => false, @@ -173,6 +173,10 @@ $search_secondary_groups = get_parameter( 'filter[search_secondary_groups]', 0 ); +$search_recursive_groups = get_parameter( + 'filter[search_recursive_groups]', + 0 +); $id_group_filter = get_parameter( 'filter[id_group_filter]', ($filter['id_group'] ?? '') @@ -356,6 +360,10 @@ if (is_ajax() === true) { $order['field'] = 'agent_name'; break; + case 'if(te.ack_utimestamp > 0, from_unixtime(te.ack_utimestamp),"") as ack_utimestamp': + $order['field'] = 'ack_utimestamp'; + break; + default: $order['field'] = $field; break; @@ -1090,6 +1098,7 @@ if ($loaded_filter !== false && $from_event_graph != 1 && isset($fb64) === false $filter_only_alert = $filter['filter_only_alert']; $search_secondary_groups = ($filter['search_secondary_groups'] ?? 0); + $search_recursive_groups = ($filter['search_recursive_groups'] ?? 0); $id_group_filter = $filter['id_group_filter']; $date_from = $filter['date_from']; $time_from = $filter['time_from']; @@ -1440,7 +1449,7 @@ if ($pure) { ).''; // If the user has administrator permission display manage tab. - if ($event_w || $event_m) { + if ($event_w === true || $event_m === true) { // Manage events. $manage_events['active'] = false; $manage_events['text'] = ''.html_print_image( @@ -1660,9 +1669,10 @@ $inputs[] = $in; // Duplicates group { events | agents }. $data = html_print_select( [ - 0 => __('All events'), - 1 => __('Group events'), - 2 => __('Group agents'), + EVENT_GROUP_REP_ALL => __('All events'), + EVENT_GROUP_REP_EVENTS => __('Group events'), + EVENT_GROUP_REP_AGENTS => __('Group agents'), + EVENT_GROUP_REP_EXTRAIDS => __('Group extra id'), ], 'group_rep', $group_rep, @@ -1710,6 +1720,28 @@ $in = '
'; $in .= $data.'
'; $inputs[] = $in; +// Search recursive groups. +$data = html_print_checkbox_switch( + 'search_recursive_groups', + $search_recursive_groups, + $search_recursive_groups, + true, + false, + 'search_in_secondary_groups(this);', + true +); + +$in = '
'; +$in .= $data; +$in .= '
'; +$inputs[] = $in; + // Search secondary groups. $data = html_print_checkbox_switch( 'search_secondary_groups', @@ -1721,8 +1753,15 @@ $data = html_print_checkbox_switch( true ); -$in = '
'; -$in .= $data.'
'; +$in = '
'; +$in .= $data; +$in .= '
'; $inputs[] = $in; // Trick view in table. @@ -1737,7 +1776,7 @@ $buttons[] = [ 'onclick' => '', ]; -if ($event_w || $event_m) { +if ($event_w === true || $event_m === true) { $buttons[] = [ 'id' => 'save-filter', 'class' => 'float-left margin-right-2 sub wand', @@ -2266,12 +2305,14 @@ try { $active_filters_div .= '
'; $active_filters_div .= '
'.__('Duplicated').'
'; $active_filters_div .= '
'; - if ($group_rep == 0) { + if ($group_rep == EVENT_GROUP_REP_ALL) { $active_filters_div .= __('All events.'); - } else if ($group_rep == 1) { + } else if ($group_rep == EVENT_GROUP_REP_EVENTS) { $active_filters_div .= __('Group events'); - } else if ($group_rep == 2) { + } else if ($group_rep == EVENT_GROUP_REP_AGENTS) { $active_filters_div .= __('Group agents.'); + } else if ($group_rep == EVENT_GROUP_REP_EXTRAIDS) { + $active_filters_div .= __('Group extra id.'); } $active_filters_div .= '
'; @@ -2361,6 +2402,16 @@ if (is_user_admin($config['id_user'])) { ); } +$array_events_actions = []; +if ($event_w === true && $readonly === false) { + $array_events_actions['in_progress_selected'] = __('In progress selected'); + $array_events_actions['validate_selected'] = __('Validate selected'); +} + +if ($event_m === true && $readonly === false) { + $array_events_actions['delete_selected'] = __('Delete selected'); +} + foreach ($event_responses as $val) { $array_events_actions[$val['id']] = $val['name']; } diff --git a/pandora_console/operation/heatmap.php b/pandora_console/operation/heatmap.php index 3ed2b8e7ce..a9ab10ed47 100644 --- a/pandora_console/operation/heatmap.php +++ b/pandora_console/operation/heatmap.php @@ -91,6 +91,10 @@ if ($is_ajax === false && $pure === false) { $header_name = __('Heatmap view'); switch ($type) { + case 3: + $header_name .= ' - '.__('Agents'); + break; + case 2: if (current($filter) == 0) { $header_name .= ' - '.__('Module group').': '.__('Not assigned'); diff --git a/pandora_console/operation/menu.php b/pandora_console/operation/menu.php index fb303dd3fa..326eecf73f 100644 --- a/pandora_console/operation/menu.php +++ b/pandora_console/operation/menu.php @@ -410,7 +410,7 @@ if ($access_console_node === true) { $user_event_filter = [ 'status' => EVENT_NO_VALIDATED, 'event_view_hr' => $config['event_view_hr'], - 'group_rep' => 1, + 'group_rep' => EVENT_GROUP_REP_EVENTS, 'tag_with' => [], 'tag_without' => [], 'history' => false, diff --git a/pandora_console/operation/users/user_edit.php b/pandora_console/operation/users/user_edit.php index a42fe2e8bc..5e8308eabc 100644 --- a/pandora_console/operation/users/user_edit.php +++ b/pandora_console/operation/users/user_edit.php @@ -211,7 +211,7 @@ if (isset($_GET['modified']) && !$view_mode) { $user_info = $upd_info; } else { if (!$error_msg) { - $error_msg = __('Error updating passwords: '); + $error_msg = __('Error updating passwords: ').($config['auth_error'] ?? ''); } $user_auth_error = $config['auth_error']; diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index 6217be599f..d6ab2ce34a 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.765 -%define release 221014 +%define release 221026 # 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 511a26cd56..cfba7a5d73 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.765 -%define release 221014 +%define release 221026 # 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 cb62e2f4a6..9033c89955 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.765 -%define release 221014 +%define release 221026 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index 8dea7613c6..53e157aec7 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -1245,6 +1245,7 @@ CREATE TABLE IF NOT EXISTS `tevent_filter` ( `tag_without` TEXT, `filter_only_alert` INT NOT NULL DEFAULT -1, `search_secondary_groups` INT NOT NULL DEFAULT 0, + `search_recursive_groups` INT NOT NULL DEFAULT 0, `date_from` date DEFAULT NULL, `date_to` date DEFAULT NULL, `source` TINYTEXT, @@ -1308,6 +1309,7 @@ CREATE TABLE IF NOT EXISTS `tusuario` ( `integria_user_level_pass` VARCHAR(45), `allowed_ip_active` TINYINT UNSIGNED DEFAULT 0, `allowed_ip_list` TEXT, + `auth_token_secret` VARCHAR(45) DEFAULT NULL, CONSTRAINT `fk_filter_id` FOREIGN KEY (`id_filter`) REFERENCES tevent_filter (`id_filter`) ON DELETE SET NULL, UNIQUE KEY `id_user` (`id_user`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 7dd36b5048..d0abcaa44b 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,5 +1,5 @@ package: pandorafms-server -Version: 7.0NG.765-221014 +Version: 7.0NG.765-221026 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 add783e6e3..9cfd75351f 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.765-221014" +pandora_version="7.0NG.765-221026" package_cpan=0 package_pandora=1 diff --git a/pandora_server/NetBSD/tentacle_server b/pandora_server/NetBSD/tentacle_server index d945a134e8..4458237003 100755 --- a/pandora_server/NetBSD/tentacle_server +++ b/pandora_server/NetBSD/tentacle_server @@ -5,7 +5,7 @@ # Tentacle have IANA assigned port tpc/41121 as official port. ########################################################################## # Copyright (c) 2007-2008 Ramon Novoa -# Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L +# Copyright (c) 2005-2022 Artica Soluciones Tecnologicas S.L # # tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for # protocol description. @@ -1740,6 +1740,19 @@ sub callback_stop { 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 ################################################################################ @@ -1753,12 +1766,20 @@ if ($> == 0 && $^O ne 'MSWin32') { # Parse command line options parse_options (); +# Try to open the log file. +if (defined($log_file)) { + open(my $fh, ">>", $log_file) || die("Error opening the log file '$log_file': $!.\n"); + close($fh); +} + # 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."); diff --git a/pandora_server/bin/tentacle_server b/pandora_server/bin/tentacle_server index feb8ecf9af..4458237003 100755 --- a/pandora_server/bin/tentacle_server +++ b/pandora_server/bin/tentacle_server @@ -5,7 +5,7 @@ # Tentacle have IANA assigned port tpc/41121 as official port. ########################################################################## # Copyright (c) 2007-2008 Ramon Novoa -# Copyright (c) 2005-2010 Artica Soluciones Tecnologicas S.L +# Copyright (c) 2005-2022 Artica Soluciones Tecnologicas S.L # # tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for # protocol description. @@ -1766,6 +1766,12 @@ if ($> == 0 && $^O ne 'MSWin32') { # Parse command line options parse_options (); +# Try to open the log file. +if (defined($log_file)) { + open(my $fh, ">>", $log_file) || die("Error opening the log file '$log_file': $!.\n"); + close($fh); +} + # Check command line arguments if ($#ARGV != -1) { print_help (); diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index 85b7db6ac4..a87b8eaf83 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -46,7 +46,7 @@ our @EXPORT = qw( # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.765"; -my $pandora_build = "221014"; +my $pandora_build = "221026"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash diff --git a/pandora_server/lib/PandoraFMS/PluginTools.pm b/pandora_server/lib/PandoraFMS/PluginTools.pm index 980dc84d9d..252a0c14e2 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.765"; -my $pandora_build = "221014"; +my $pandora_build = "221026"; our $VERSION = $pandora_version." ".$pandora_build; our %EXPORT_TAGS = ( 'all' => [ qw() ] ); diff --git a/pandora_server/pandora_server.redhat.spec b/pandora_server/pandora_server.redhat.spec index b26554742d..85c9120e6b 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.765 -%define release 221014 +%define release 221026 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server.spec b/pandora_server/pandora_server.spec index 1c705de963..787073d078 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.765 -%define release 221014 +%define release 221026 Summary: Pandora FMS Server Name: %{name} diff --git a/pandora_server/pandora_server_installer b/pandora_server/pandora_server_installer index 7aa8c6f4de..bc70c102c4 100755 --- a/pandora_server/pandora_server_installer +++ b/pandora_server/pandora_server_installer @@ -9,7 +9,7 @@ # ********************************************************************** PI_VERSION="7.0NG.765" -PI_BUILD="221014" +PI_BUILD="221026" MODE=$1 if [ $# -gt 1 ]; then diff --git a/pandora_server/util/pandora_db.pl b/pandora_server/util/pandora_db.pl index 21efbbd6a4..9b8ddc6c86 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.765 Build 221014"; +my $version = "7.0NG.765 Build 221026"; # Pandora server configuration my %conf; diff --git a/pandora_server/util/pandora_manage.pl b/pandora_server/util/pandora_manage.pl index f7c72111b2..b0e964727d 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.765 Build 221014"; +my $version = "7.0NG.765 Build 221026"; # save program name for logging my $progname = basename($0); @@ -251,6 +251,11 @@ sub help_screen{ print "\nEVENTS\n\n" unless $param ne ''; help_screen_line('--event_in_progress', ' ', 'Set event in progress'); + print "\nGIS\n\n" unless $param ne ''; + help_screen_line('--get_gis_agent', ' ', 'Gets agent GIS information'); + help_screen_line('--insert_gis_data', ' [] [] []', 'Sets new GIS data for specified agent'); + + print "\n"; exit; } @@ -261,7 +266,7 @@ sub help_screen{ sub api_call($$$;$$$$) { my ($pa_config, $op, $op2, $id, $id2, $other, $return_type) = @_; my $content = undef; - + eval { # Set the parameters for the POST request. my $params = {}; @@ -275,10 +280,11 @@ sub api_call($$$;$$$$) { $params->{"other"} = $other; $params->{"return_type"} = $return_type; $params->{"other_mode"} = "url_encode_separator_|"; - + # Call the API. my $ua = new LWP::UserAgent; my $url = $pa_config->{"console_api_url"}; + my $response = $ua->post($url, $params); if ($response->is_success) { @@ -288,7 +294,7 @@ sub api_call($$$;$$$$) { $content = $response->decoded_content(); } }; - + return $content; } @@ -567,8 +573,8 @@ sub pandora_create_user ($$$$$) { exit; } - return db_insert ($dbh, 'id_user', 'INSERT INTO tusuario (id_user, fullname, password, comments, is_admin) - VALUES (?, ?, ?, ?, ?)', safe_input($name), safe_input($name), $password, safe_input($comments), $is_admin); + return db_insert ($dbh, 'id_user', 'INSERT INTO tusuario (id_user, fullname, password, is_admin, comments) + VALUES (?, ?, ?, ?, ?)', safe_input($name), safe_input($name), $password, $is_admin ? '1' : '0', decode_entities($comments)); } ########################################################################## @@ -8045,6 +8051,14 @@ sub pandora_manage_main ($$$) { param_check($ltotal, 4, 5); cli_agent_update_custom_fields(); } + elsif ($param eq '--get_gis_agent') { + param_check($ltotal, 1, 0); + cli_get_gis_agent(); + } + elsif ($param eq '--insert_gis_data'){ + param_check($ltotal, 4, 0); + cli_insert_gis_data(); + } else { print_log "[ERROR] Invalid option '$param'.\n\n"; $param = ''; @@ -8765,3 +8779,32 @@ sub pandora_validate_alert_id($$$$) { return 1; } + +############################################################################## +# Get GIS data from agent +############################################################################## + +sub cli_get_gis_agent(){ + + my $agent_id = @ARGV[2]; + + my $result = api_call(\%conf,'get', 'gis_agent', $agent_id); + print "$result \n\n "; + +} + +############################################################################## +# Set GIS data for specified agent +############################################################################## + +sub cli_insert_gis_data(){ + + my ($agent_id, $latitude, $longitude, $altitude) = @ARGV[2..5]; + my $agent_id = @ARGV[2]; + my @position = @ARGV[3..5]; + my $other = join('|', @position); + + my $result = api_call(\%conf,'set', 'gis_agent_only_position', $agent_id, undef, "$other"); + print "$result \n\n "; + +} diff --git a/pandora_server/util/tentacle_serverd b/pandora_server/util/tentacle_serverd index 0c0f35ff97..80e8364946 100755 --- a/pandora_server/util/tentacle_serverd +++ b/pandora_server/util/tentacle_serverd @@ -119,7 +119,6 @@ case "$1" in rc_status -v else echo "Tentacle Server could not be started." - echo "Verify that Tentacle port is not used." rc_failed 7 # program not running fi diff --git a/tentacle/NetBSD/tentacle_server b/tentacle/NetBSD/tentacle_server deleted file mode 100755 index d945a134e8..0000000000 --- a/tentacle/NetBSD/tentacle_server +++ /dev/null @@ -1,1869 +0,0 @@ -#!/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 -# 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 >> [I] - -=head1 DESCRIPTION - -B is a server for B, a B 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) are designed to be run from the command line or called from a shell script, and B. - -=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 [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 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 = ; - } - - 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 = ) { - 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(); -} - -################################################################################ -# 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; -} - -# 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 >> Root directory to store the files received by the server - -=back - -=head1 OPTIONS - -=over - -=item I<-a ip_address> Address to B on (default I<0.0.0.0>). - -=item I<-c number> B number of simultaneous B (default I<10>). - -=item I<-d> Run as B. - -=item I<-e cert> B file. Enables SSL. - -=item I<-f ca_cert> Verify that the peer certificate is signed by a B. - -=item I<-h> Show B. - -=item I<-i> B. - -=item I<-k key> B file. - -=item I<-m size> B in bytes (default I<2000000b>). - -=item I<-o> Enable file B. - -=item I<-p port> B on (default I<41121>). - -=item I<-q> B. Do now print error messages. - -=item I<-r number> B for network opertions (default I<3>). - -=item I<-t time> B for network operations in B (default I<1s>). - -=item I<-v> Be B. - -=item I<-w> Prompt for B. - -=item I<-x> pwd B. - -=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, L, L, L, L - - -=head1 LICENSE - -This is released under the GNU Lesser General Public License. - -=head1 SEE ALSO - -L, L, L, L, L - -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 index 8eb5aa3203..4458237003 100755 --- a/tentacle/tentacle_server +++ b/tentacle/tentacle_server @@ -5,7 +5,7 @@ # Tentacle have IANA assigned port tpc/41121 as official port. ########################################################################## # Copyright (c) 2007-2008 Ramon Novoa -# Copyright (c) 2005-2021 Artica Soluciones Tecnologicas S.L +# Copyright (c) 2005-2022 Artica Soluciones Tecnologicas S.L # # tentacle_server.pl Tentacle Server. See https://pandorafms.com/docs/ for # protocol description. @@ -230,7 +230,6 @@ sub print_help { 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 Storage directory\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"); @@ -1767,6 +1766,12 @@ if ($> == 0 && $^O ne 'MSWin32') { # Parse command line options parse_options (); +# Try to open the log file. +if (defined($log_file)) { + open(my $fh, ">>", $log_file) || die("Error opening the log file '$log_file': $!.\n"); + close($fh); +} + # Check command line arguments if ($#ARGV != -1) { print_help (); diff --git a/tentacle/util/tentacle_serverd b/tentacle/util/tentacle_serverd index 0c0f35ff97..80e8364946 100755 --- a/tentacle/util/tentacle_serverd +++ b/tentacle/util/tentacle_serverd @@ -119,7 +119,6 @@ case "$1" in rc_status -v else echo "Tentacle Server could not be started." - echo "Verify that Tentacle port is not used." rc_failed 7 # program not running fi