Merge branch 'ent-6858-Goliat-opensource' into 'develop'

Backup upload

See merge request artica/pandorafms!3936
This commit is contained in:
Daniel Rodriguez 2021-05-12 13:10:48 +00:00
commit 13fa1159ce
14 changed files with 2728 additions and 55 deletions

View File

@ -74,6 +74,10 @@ enterprise/extensions/ipam
enterprise/extensions/disabled/visual_console_manager.php
enterprise/extensions/visual_console_manager.php
pandora_console/extensions/net_tools.php
enterprise/godmode/agentes/module_manager_editor_web.php
enterprise/include/ajax/web_server_module_debug.php
enterprise/include/class/WebServerModuleDebug.class.php
enterprise/include/styles/WebServerModuleDebug.css
include/lib/WSManager.php
include/lib/WebSocketServer.php
include/lib/WebSocketUser.php

View File

@ -1,22 +1,38 @@
<?php
/**
* Module Manager main script.
*
* @category Module
* @package Pandora FMS
* @subpackage Agent Configuration
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* 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 for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Pandora FMS - http://pandorafms.com
// ==================================================
// Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
// Please see http://pandorafms.org for full contribution list
// 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 for version 2.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You can redefine $url and unset $id_agente to reuse the form. Dirty (hope temporal) hack
if (isset($id_agente)) {
$url = 'index.php?sec=gagente&sec2=godmode/agentes/configurar_agente&tab=module&id_agente='.$id_agente;
} else {
$url = 'index.php?sec=gagente&sec2=godmode/agentes/configurar_agente&tab=module';
}
// You can redefine $url and unset $id_agente to reuse the form. Dirty (hope temporal) hack.
$url_id_agente = (isset($id_agente) === true) ? '&id_agente='.$id_agente : '';
$url = sprintf(
'index.php?sec=gagente&sec2=godmode/agentes/configurar_agente&tab=module%s',
$url_id_agente
);
enterprise_include('godmode/agentes/module_manager.php');
$isFunctionPolicies = enterprise_include_once('include/functions_policies.php');
@ -56,7 +72,7 @@ echo __('Search').' '.html_print_input_text(
);
html_print_input_hidden('search', 1);
// Search string filter form.
if (($policy_page) || (isset($agent))) {
if (($policy_page !== false) || (isset($agent) === true)) {
echo '<form id="" method="post" action="">';
} else {
echo '<form id="create_module_type" method="post" action="'.$url.'">';
@ -73,25 +89,31 @@ echo '</form>';
$network_available = db_get_sql(
'SELECT count(*)
FROM tserver
WHERE server_type = 1'
WHERE server_type = '.SERVER_TYPE_NETWORK
);
// POSTGRESQL AND ORACLE COMPATIBLE.
$wmi_available = db_get_sql(
'SELECT count(*)
FROM tserver
WHERE server_type = 6'
WHERE server_type = '.SERVER_TYPE_WMI
);
// POSTGRESQL AND ORACLE COMPATIBLE.
$plugin_available = db_get_sql(
'SELECT count(*)
FROM tserver
WHERE server_type = 4'
WHERE server_type = '.SERVER_TYPE_PLUGIN
);
// POSTGRESQL AND ORACLE COMPATIBLE.
$prediction_available = db_get_sql(
'SELECT count(*)
FROM tserver
WHERE server_type = 5'
WHERE server_type = '.SERVER_TYPE_PREDICTION
);
// POSTGRESQL AND ORACLE COMPATIBLE.
$web_available = db_get_sql(
'SELECT count(*)
FROM tserver
WHERE server_type = '.SERVER_TYPE_WEB
);
// POSTGRESQL AND ORACLE COMPATIBLE.
// Development mode to use all servers.
@ -122,6 +144,10 @@ if ($prediction_available) {
$modules['predictionserver'] = __('Create a new prediction server module');
}
if ($web_available) {
$modules['webserver'] = __('Create a new web Server module');
}
if (enterprise_installed()) {
set_enterprise_module_types($modules);
}
@ -298,6 +324,7 @@ if ($module_action === 'delete') {
switch ($config['dbtype']) {
case 'mysql':
case 'postgresql':
default:
$result = db_process_sql_delete(
'tagente_estado',
['id_agente_modulo' => $id_agent_module_del]
@ -388,10 +415,8 @@ if ($module_action === 'delete') {
}
}
// Check for errors.
if ($error != 0) {
} else {
if ((int) $error == 0) {
$count_correct_delete_modules++;
}
}
@ -489,6 +514,7 @@ switch ($sortField) {
switch ($config['dbtype']) {
case 'mysql':
case 'postgresql':
default:
$order[] = [
'field' => 'tagente_modulo.nombre',
'order' => 'ASC',
@ -509,6 +535,7 @@ switch ($sortField) {
switch ($config['dbtype']) {
case 'mysql':
case 'postgresql':
default:
$order[] = [
'field' => 'tagente_modulo.nombre',
'order' => 'DESC',
@ -523,6 +550,10 @@ switch ($sortField) {
break;
}
break;
default:
// Do none.
break;
}
break;
@ -543,6 +574,10 @@ switch ($sortField) {
'order' => 'DESC',
];
break;
default:
// Do none.
break;
}
break;
@ -563,6 +598,10 @@ switch ($sortField) {
'order' => 'DESC',
];
break;
default:
// Do none.
break;
}
break;
@ -583,6 +622,10 @@ switch ($sortField) {
'order' => 'DESC',
];
break;
default:
// Do none.
break;
}
break;
@ -598,6 +641,7 @@ switch ($sortField) {
switch ($config['dbtype']) {
case 'mysql':
case 'postgresql':
default:
$order[] = [
'field' => 'nombre',
'order' => 'ASC',
@ -622,7 +666,7 @@ if (!empty($order)) {
$first = true;
foreach ($order as $ord) {
if ($first) {
if ($first === true) {
$first = false;
} else {
$order_sql .= ',';
@ -635,7 +679,10 @@ foreach ($order as $ord) {
$limit = (int) $config['block_size'];
$offset = (int) get_parameter('offset');
$params = ($checked) ? 'tagente_modulo.*, tmodule_group.*' : implode(
if ((bool) $checked === true) {
$params = 'tagente_modulo.*, tmodule_group.*';
} else {
$params = implode(
',',
[
'tagente_modulo.id_agente_modulo',
@ -659,7 +706,8 @@ $params = ($checked) ? 'tagente_modulo.*, tmodule_group.*' : implode(
'warning_inverse',
'id_policy_module',
]
);
);
}
$where = sprintf('delete_pending = 0 AND id_agente = %s', $id_agente);
@ -686,7 +734,11 @@ if (isset($config['paginate_module'])) {
if ($paginate_module) {
if (!isset($limit_sql)) {
$limit_sql = " LIMIT $offset, $limit ";
$limit_sql = sprintf(
'LIMIT %s, %s',
$offset,
$limit
);
}
} else {
$limit_sql = '';
@ -732,7 +784,13 @@ if ($modules === false) {
}
// Prepare pagination.
$url = '?'.'sec=gagente&'.'tab=module&'.'sec2=godmode/agentes/configurar_agente&'.'id_agente='.$id_agente.'&'.'sort_field='.$sortField.'&'.'&sort='.$sort.'&'.'search_string='.urlencode($search_string);
$url = sprintf(
'?sec=gagente&tab=module&sec2=godmode/agentes/configurar_agente&id_agente=%s&sort_field=%s&sort=%s&search_string=%s',
$id_agente,
$sortField,
$sort,
urlencode($search_string)
);
if ($paginate_module) {
ui_pagination($total_modules, $url);

View File

@ -682,6 +682,22 @@ switch ($moduletype) {
include 'module_manager_editor_wmi.php';
break;
case 'webserver':
case MODULE_WEB:
$moduletype = MODULE_WEB;
// Remove content of $ip_target when it is ip_agent because
// it is used as HTTP auth (server) ....ONLY IN NEW MODULE!!!
if (empty($id_agent_module)
&& ($ip_target === agents_get_address($id_agente))
) {
$ip_target = '';
}
$categories = [9];
include 'module_manager_editor_common.php';
include 'module_manager_editor_web.php';
break;
// WARNING: type 7 is reserved on enterprise.
default:
if (enterprise_include(

View File

@ -0,0 +1,468 @@
<?php
/**
* Web Module Editor for Module Manager.
*
* @category Module manager
* @package Pandora FMS
* @subpackage Module manager
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* 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 for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
enterprise_include_once('include/functions_policies.php');
$disabledBecauseInPolicy = false;
$disabledTextBecauseInPolicy = '';
$classdisabledBecauseInPolicy = '';
$page = get_parameter('page', '');
if (strstr($page, 'policy_modules') === false) {
if ($config['enterprise_installed']) {
if (policies_is_module_linked($id_agent_module) == 1) {
$disabledBecauseInPolicy = 1;
} else {
$disabledBecauseInPolicy = 0;
}
} else {
$disabledBecauseInPolicy = false;
}
if ($disabledBecauseInPolicy) {
$disabledTextBecauseInPolicy = 'disabled = "disabled"';
$classdisabledBecauseInPolicy = 'readonly';
}
}
global $id_agente;
$extra_title = __('Web server module');
// Div for modal.
html_print_div(
[
'id' => 'modal',
'style' => 'display: none;',
]
);
require_once $config['homedir'].'/include/ajax/web_server_module_debug.php';
define('ID_NETWORK_COMPONENT_TYPE', 7);
if (!$tcp_port && !$id_agent_module) {
$tcp_port = 80;
}
// plugin_server is the browser id
if ($plugin_user == '' && !$id_agent_module) {
$plugin_user = get_product_name().' / Webcheck';
}
// plugin_server is the referer
if ($plugin_pass == '' && !$id_agent_module) {
$plugin_pass = 1;
}
if (empty($update_module_id)) {
// Function in module_manager_editor_common.php
add_component_selection(ID_NETWORK_COMPONENT_TYPE);
} else {
// TODO: Print network component if available
}
$data = [];
$data[0] = __('Web checks');
$adopt = false;
if (isset($id_agent_module)) {
$adopt = enterprise_hook('policies_is_module_adopt', [$id_agent_module]);
}
$id_policy_module = (int) get_parameter('id_policy_module', '');
if ($id_policy_module) {
$module = enterprise_hook('policies_get_module', [$id_policy_module]);
$plugin_parameter = $module['plugin_parameter'];
}
if ((bool) $adopt === false) {
$data[1] = html_print_textarea(
'plugin_parameter',
15,
65,
$plugin_parameter,
$disabledTextBecauseInPolicy,
true
);
} else {
$data[1] = html_print_textarea(
'plugin_parameter',
15,
65,
$plugin_parameter,
false,
true
);
}
$table_simple->colspan['web_checks'][1] = 2;
// Disable debug button if module has not started.
if ($id_agent_module > 0
&& db_get_value_filter(
'debug_content',
'tagente_modulo',
['id_agente_modulo' => $id_agent_module]
) !== null
) {
$disableDebug = false;
$hintDebug = __('Debug remotely this module');
} else {
$disableDebug = true;
$hintDebug = __('Debug this module once it has been initialized');
}
$suc_err_check = ' <span id="check_conf_suc" class="checks invisible">'.html_print_image('/images/ok.png', true).'</span>';
$suc_err_check .= ' <span id="check_conf_err" class="checks invisible">'.html_print_image('/images/error_red.png', true).'</span>';
$data[2] = html_print_button(
__('Load basic'),
'btn_loadbasic',
false,
'',
'class="sub config"',
true
).ui_print_help_tip(__('Load a basic structure on Web Checks'), true);
$data[2] .= '<br><br>'.html_print_button(
__('Check'),
'btn_checkconf',
false,
'',
'class="sub upd"',
true
).ui_print_help_tip(__('Check the correct structure of the WebCheck'), true).$suc_err_check;
$data[2] .= '<br><br>'.html_print_button(
__('Debug'),
'btn_debugModule',
$disableDebug,
'',
'class="sub config" onClick="loadDebugWindow()"',
true
).ui_print_help_tip($hintDebug, true);
push_table_simple($data, 'web_checks');
$http_checks_type = [
0 => 'Anyauth',
1 => 'NTLM',
2 => 'DIGEST',
3 => 'BASIC',
];
$data = [];
$data[0] = __('Check type');
$data[1] = html_print_select($http_checks_type, 'tcp_port', $tcp_port, false, '', '', true, false, false);
push_table_advanced($data, 'web_0');
$data = [];
$data[0] = __('Requests');
$data[1] = html_print_input_text('plugin_pass', $plugin_pass, '', 10, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
$data[2] = '';
$data[3] = __('Agent browser id');
$data[4] = html_print_input_text('plugin_user', $plugin_user, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
push_table_advanced($data, 'web_1');
$data = [];
$data[0] = __('HTTP auth (login)');
$data[1] = html_print_input_text('http_user', $plugin_parameter_http_user, '', 10, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
$data[2] = '';
$data[3] = __('HTTP auth (password)');
$data[4] = html_print_input_password('http_pass', $plugin_parameter_http_pass, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
push_table_advanced($data, 'web_2');
$data = [];
$data[0] = __('Proxy URL');
$data[1] = html_print_input_text('snmp_oid', $snmp_oid, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
$data[2] = $data[3] = $data[4] = '';
push_table_advanced($data, 'web_3');
$data = [];
$data[0] = __('Proxy auth (login)');
$data[1] = html_print_input_text('tcp_send', $tcp_send, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
$data[2] = '';
$data[3] = __('Proxy auth (pass)');
$data[4] = html_print_input_password('tcp_rcv', $tcp_rcv, '', 30, 0, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
push_table_advanced($data, 'web_4');
$data = [];
$data[0] = __('Proxy auth (server)');
$data[1] = html_print_input_text('ip_target', $ip_target, '', 30, 100, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
$data[2] = '';
$data[3] = __('Proxy auth (realm)');
$data[4] = html_print_input_text('snmp_community', $snmp_community, '', 30, 100, true, $disabledBecauseInPolicy, false, '', $classdisabledBecauseInPolicy);
push_table_advanced($data, 'web_5');
// Add some strings to be used from javascript
$texts = [
'lines_before_begin' => __('First line must be "task_begin"'),
'missed_begin' => __('Webchecks configuration is empty'),
'missed_end' => __('Last line must be "task_end"'),
'lines_after_end' => __('Last line must be "task_end"'),
'unknown_token' => __("There is a line with a unknown token 'token_fail'."),
'missed_get_post' => __("There isn't get or post"),
'correct' => __('Web checks are built correctly'),
];
foreach ($texts as $code => $text) {
echo '<span class="invisible" id="'.$code.'">'.$text.'</span>';
}
?>
<script type="text/javascript">
var supported_tokens = [
"task_begin",
"post",
"variable_name",
"variable_value",
"cookie",
"resource",
"get",
"check_string",
"check_not_string",
"get_content_advanced",
"get_content",
"debug",
"task_end",
"head",
"http_auth_user",
"http_auth_pass"
];
$(document).ready(function() {
var plugin_parameter = $("#textarea_plugin_parameter");
var http_auth_user = $('#text-http_user');
var http_auth_pass = $('#password-http_pass');
$(plugin_parameter).keyup(function() {
// Check and fill textbox.
if ($(plugin_parameter).val() == '') {
$('#button-btn_loadbasic').removeAttr('disabled');
} else {
$('#button-btn_loadbasic').attr('disabled', 'disabled');
}
// Update http_auth_user from conf data
var http_auth_user_value = get_module_token_from_config('http_auth_user', plugin_parameter, "\n");
if (http_auth_user_value != "") {
http_auth_user.val(http_auth_user_value);
}
// Update http_auth_pass from conf data
var http_auth_pass_value = get_module_token_from_config('http_auth_pass', plugin_parameter, "\n");
if (http_auth_pass_value != "") {
http_auth_pass.val(http_auth_pass_value);
}
});
$('#button-btn_loadbasic').click(function() {
if ($(plugin_parameter).val() != '') {
return;
}
$(plugin_parameter).val(
'task_begin\ncookie 0\nresource 0\ntask_end');
$('#button-btn_loadbasic').attr('disabled', 'disabled');
// Hide success and error indicators
$('.checks').hide();
});
$('#button-btn_checkconf').click(function() {
var msg_error = '';
if (plugin_parameter.val() == '') {
msg_error = 'missed_begin';
} else {
var lines = plugin_parameter.val().split("\n");
var started = false;
var ended = false;
var lines_after_end = false;
var lines_before_begin = false;
var token_fail = false;
var token_get_post = false;
var token_check = true;
var str_token_fail = '';
for (i = 0; i < lines.length; i++) {
if (lines[i].match(/^\s*$/)) {
// Empty line
continue;
} else if (!started) {
if (lines[i].match(/^task_begin\s*$/)) {
started = true;
} else {
// Found a not empty line before task_begin
lines_before_begin = true;
break;
}
}
if (lines[i].match(/^task_end\s*$/)) {
ended = true;
continue;
}
//Check token is correct
if (!lines[i].match(/^([\s])*[#]/)) {
var token = lines[i].match(/^([^\s]+)\s*/);
if (typeof(token) == 'object') {
token = token[1];
if ((!token_get_post) && (token == 'get' || token == 'post' || token == 'header')) {
token_get_post = true;
continue;
}
if (token == 'check_string') {
if (token_get_post) {
token_check = true;
continue;
} else {
token_check = false;
continue;
}
}
if ($.inArray(token, supported_tokens) == -1) {
token_fail = true;
str_token_fail = token;
break;
}
}
}
}
}
var msg_error = '';
if (token_fail) {
var temp_msg = $("#unknown_token").html();
temp_msg = temp_msg.replace(/['](.*)[']/, "'" + str_token_fail + "'");
$("#unknown_token").html(temp_msg);
msg_error = 'unknown_token';
} else if (lines_before_begin) {
msg_error = 'lines_before_begin';
} else if (!started) {
msg_error = 'missed_begin';
} else if (!ended) {
msg_error = 'missed_end';
} else if (lines_after_end) {
msg_error = 'lines_after_end';
} else if (!token_check) {
msg_error = 'missed_get_post';
} else {
msg_error = 'correct';
}
if (msg_error == 'correct') {
$('#check_conf_suc').find('img').eq(0)
.attr('title', $('#' + msg_error).html());
$('#check_conf_err').hide();
$('#check_conf_suc').show();
} else {
$('#check_conf_err').find('img').eq(0)
.attr('title', $('#' + msg_error).html());
$('#check_conf_suc').hide();
$('#check_conf_err').show();
}
});
$(plugin_parameter).trigger('keyup');
http_auth_user.keyup(function() {
config = plugin_parameter.val();
if (config.search("http_auth_user") == -1) {
var http_auth_user_end =
"http_auth_user " + this.value + "\n" + "task_end" + "\n";
plugin_parameter.val(config.replace(/^task_end.*$/m, http_auth_user_end));
} else {
plugin_parameter.val(
config.replace(/^http_auth_user.*$/m, "http_auth_user " + this.value)
);
// Hide success and error indicators
$(".checks").hide();
}
});
http_auth_pass.keyup(function() {
config = plugin_parameter.val();
if (config.search("http_auth_pass") == -1) {
var http_auth_pass_end =
"http_auth_pass " + this.value + "\n" + "task_end" + "\n";
plugin_parameter.val(config.replace(/^task_end.*$/m, http_auth_pass_end));
} else {
plugin_parameter.val(
config.replace(/^http_auth_pass.*$/m, "http_auth_pass " + this.value)
);
// Hide success and error indicators
$(".checks").hide();
}
});
});
function get_module_token_from_config(token_name, plugin_parameter, separator) {
var return_var = "";
if(token_name == null || token_name == '') {
return '';
}
data = plugin_parameter.val().split(separator);
len = data.length;
for (i = 0; i < len; i++) {
if (data[i][0] == "#") continue;
tokens = data[i].split(" ");
if (tokens.length == 0) continue;
token = tokens.shift();
if (token == token_name ) return_var = tokens.join(" ");
}
return_var = $.trim(return_var);
return return_var;
}
</script>

View File

@ -0,0 +1,74 @@
<?php
/**
* Web Server Module Debug ajax controller.
*
* @category Web Server Module Debug
* @package Pandora FMS
* @subpackage Module Debug
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2021 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* 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 for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
global $id_agent_module;
// Module Debug Class.
require_once $config['homedir'].'/include/class/WebServerModuleDebug.class.php';
// This page.
$ajaxPage = $config['homedir'].'/include/ajax/web_server_module_debug';
// Control call flow for debug window.
try {
// Return of id of the agent module in AJAX.
if (is_ajax()) {
$id_agent_module = get_parameter('idAgentModule');
}
// User access and validation is being processed on class constructor.
$obj = new WebServerModuleDebug($ajaxPage, $id_agent_module);
} catch (Exception $e) {
if (is_ajax()) {
echo json_encode(['error' => '[WebServerModuleDebug]'.$e->getMessage() ]);
exit;
} else {
echo '[WebServerModuleDebug]'.$e->getMessage();
}
// Stop this execution, but continue 'globally'.
return;
}
// AJAX controller.
if (is_ajax()) {
$method = get_parameter('method');
if (method_exists($obj, $method) === true) {
$obj->{$method}();
} else {
$obj->error('Method not found. ['.$method.']');
}
// Stop any execution.
exit;
} else {
// Run.
$obj->run();
}

View File

@ -0,0 +1,407 @@
<?php
/**
* WebServer Module debug feature.
*
* @category Class
* @package Pandora FMS
* @subpackage Web Server Module
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2005-2020 Artica Soluciones Tecnologicas
* Please see http://pandorafms.org for full contribution list
* 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 for version 2.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* ============================================================================
*/
// Begin.
global $config;
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
/**
* Class WebServerModuleDebug.
*/
class WebServerModuleDebug extends Wizard
{
/**
* Controller Url.
*
* @var string
*/
private $ajaxController;
/**
* Timeout for HTTP requests.
*
* @var integer
*/
private $requestTimeout;
/**
* CURL Query.
*
* @var string
*/
private $query;
/**
* Id of the current module.
*
* @var integer
*/
private $idAgentModule;
/**
* Class constructor.
*
* @param string $ajaxController Ajax Page Controller.
* @param integer $idAgentModule Id of the module.
*/
public function __construct(string $ajaxController, int $idAgentModule)
{
global $config;
// Check access.
check_login();
if (! check_acl($config['id_user'], 0, 'AR')) {
db_pandora_audit(
'ACL Violation',
'Trying to access event viewer'
);
if (is_ajax()) {
echo json_encode(['error' => 'noaccess']);
}
include 'general/noaccess.php';
exit;
}
// Parameter assigments.
$this->ajaxController = $ajaxController;
$this->query = '';
$this->idAgentModule = $idAgentModule;
// Hardcoded request timeout.
$this->requestTimeout = 15;
return $this;
}
/**
* Run Module Debug window.
*
* @return void
*/
public function run()
{
// Added all necessary basic files for QueryResult.
ui_require_css_file('ace');
ui_require_javascript_file('ace', 'include/javascript/ace/');
// Load Javascript.
$this->loadJS();
// CSS.
ui_require_css_file('wizard');
ui_require_css_file('discovery');
// Specific CSS for this feature.
ui_require_css_file('WebServerModuleDebug', '/include/styles/', true);
}
/**
* Show the modal with the QueryResult.
*
* @return void
*/
public function showWebServerDebug()
{
// Show QueryResult editor.
ui_query_result_editor('webserverdebug');
// Spinner for wait loads.
html_print_div(
[
'id' => 'WebServerDebugSpinner',
'style' => 'visibility: hidden;',
'content' => __('Performing query. Please wait.').'&nbsp;'.html_print_image('images/spinner.gif', true),
]
);
?>
<script type="text/javascript">
$(document).ready(function(){
// Query section
var query = ace.edit("webserverdebug_editor");
let queryDefined = "<?php echo $this->defineQuery(); ?>";
let queryRegex = /([-]+[a-zA-Z]\s)|(([-]{2})+[a-z]+[-]*[a-z]*)/g;
query.setValue(queryDefined.replace(queryRegex, "\n$&"));
query.clearSelection();
// Result section
var results = ace.edit("webserverdebug_view");
var text = '';
results.setTheme("ace/theme/textmate");
results.session.setMode("ace/mode/json");
results.renderer.setShowGutter(false);
results.setReadOnly(true);
results.setShowPrintMargin(false);
$("#submit-execute_query").click(function() {
// Show the spinner.
showSpinner(true);
// Empty the results container.
results.setValue("");
// Get the entire text.
text = query.getValue();
// There are not values in the query section.
if (text === null || text === undefined) {
results.setValue('<?php echo __('No results'); ?>');
results.clearSelection();
// Hide spinner.
showSpinner(false);
return;
}
// Clean the carriage jumps.
text = text.split("\n").join("");
// Call to the method for execute the command.
$.ajax({
method: "post",
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
data: {
page: "<?php echo $this->ajaxController; ?>",
method: "executeCommand",
text: text,
idAgentModule: "<?php echo $this->idAgentModule; ?>",
},
datatype: "json",
success: function(result) {
results.setValue(result);
},
error: function(e) {
results.setValue('<?php echo __('Error performing execution'); ?>');
},
complete: function() {
results.clearSelection();
showSpinner(false);
}
});
});
});
</script>
<?php
}
/**
* Definition of the query
*
* @return string
*/
private function defineQuery()
{
// Get the value of the debug_content.
$outputDebugQuery = db_get_value_filter(
'debug_content',
'tagente_modulo',
[
'id_agente_modulo' => $this->idAgentModule,
]
);
$this->query = ($outputDebugQuery !== false) ? $outputDebugQuery : __('Please, wait for a first execution of module');
return $this->query;
}
/**
* Perform the cURL execution.
*
* @return void
* @throws Exception $e Error message.
*/
public function executeCommand()
{
try {
$executionForPerform = io_safe_output(get_parameter('text'));
// If the execution comes empty.
if (empty($executionForPerform) === true) {
throw new Exception('Execution failed');
}
// For security reasons, only allow the 'curl' command.
$executionForPerform = strstr($executionForPerform, 'curl');
// Avoid pipes or concatenation of commands.
$unallowedChars = [
'|',
'&',
'||',
'&&',
';',
'\n',
];
$executionForPerform = str_replace(
$unallowedChars,
' ',
$executionForPerform
);
// Set execution timeout.
$executionForPerform .= sprintf(
$executionForPerform.' -m %d',
$this->requestTimeout
);
// Perform the execution.
system($executionForPerform, $returnCode);
// If execution does not got well.
if ($returnCode != 0) {
switch ($returnCode) {
case '2':
throw new Exception('Failed to initialize. Review the syntax.');
case '3':
throw new Exception('URL malformed. The syntax was not correct.');
case '5':
throw new Exception('Couldn\'t resolve proxy. The given proxy host could not be resolved.');
case '6':
throw new Exception('Couldn\'t resolve host. The given remote host could not be resolved.');
case '7':
throw new Exception('Failed to connect to host.');
default:
throw new Exception('Failed getting data.');
}
}
} catch (Exception $e) {
// Show execution error message.
echo __($e->getMessage());
}
exit;
}
/**
* Loads JS and return code.
*
* @return string
*/
public function loadJS()
{
$str = '';
ob_start();
?>
<script type="text/javascript">
$(document).ready(function(){
$('#button-btn_debugModule').click(function() {
load_modal({
target: $("#modal"),
form: "add_module_form",
url: "<?php echo ui_get_full_url('ajax.php', false, false, false); ?>",
ajax_callback: showMsg,
modal: {
title: "<?php echo __('Debug'); ?>",
},
extradata: [
{
name: "idAgentModule",
value: "<?php echo $this->idAgentModule; ?>"
}],
onshow: {
page: "<?php echo $this->ajaxController; ?>",
width: 800,
method: "showWebServerDebug"
}
});
});
});
/**
* Toggle the visibility of spinner.
*/
function showSpinner(setVisibility) {
var spinner = $('#WebServerDebugSpinner');
if (setVisibility) {
spinner.css('visibility', 'visible');
} else {
spinner.css('visibility', 'hidden');
}
}
/**
* Process ajax responses and shows a dialog with results.
*/
function showMsg(data) {
var title = "<?php echo __('Success'); ?>";
var text = "";
var failed = 0;
try {
data = JSON.parse(data);
text = data["result"];
} catch (err) {
title = "<?php echo __('Failed'); ?>";
text = err.message;
failed = 1;
}
if (!failed && data["error"] != undefined) {
title = "<?php echo __('Failed'); ?>";
text = data["error"];
failed = 1;
}
if (data["report"] != undefined) {
data["report"].forEach(function(item) {
text += "<br>" + item;
});
}
$("#msg").empty();
$("#msg").html(text);
$("#msg").dialog({
width: 450,
position: {
my: "center",
at: "center",
of: window,
collision: "fit"
},
title: title
});
}
</script>
<?php
// Get the JS script.
$str = ob_get_clean();
// Return the loaded JS.
echo $str;
return $str;
}
}

View File

@ -0,0 +1,10 @@
/* Web Server Module Debug Specific CSS file */
.query_result_editor,
.query_result_view {
min-height: 45em;
height: 45em;
}
#query_result_container {
margin-top: 30px;
}

View File

@ -38,6 +38,7 @@ use PandoraFMS::DiscoveryServer;
use PandoraFMS::WMIServer;
use PandoraFMS::PluginServer;
use PandoraFMS::PredictionServer;
use PandoraFMS::WebServer;
# Constants for Win32 services.
use constant WIN32_SERVICE_STOPPED => 0x01;
@ -123,6 +124,7 @@ sub pandora_startup () {
push (@Servers, new PandoraFMS::WMIServer (\%Config, $DBH));
push (@Servers, new PandoraFMS::PluginServer (\%Config, $DBH));
push (@Servers, new PandoraFMS::PredictionServer (\%Config, $DBH));
push (@Servers, new PandoraFMS::WebServer (\%Config, $DBH));
} else {
# Metaconsole service modules are run by the prediction server
push (@Servers, new PandoraFMS::PredictionServer (\%Config, $DBH));

View File

@ -424,11 +424,11 @@ update_parent 1
# openstreetmaps_description 1
# Enable (1) or disable (0) Pandora FMS Web Server/Goliat (PANDORA FMS ENTERPRISE ONLY).
# Enable (1) or disable (0) Pandora FMS Web Server/Goliat.
webserver 1
# Number of threads for the Web Server/Goliat (PANDORA FMS ENTERPRISE ONLY).
# Number of threads for the Web Server/Goliat.
web_threads 1

View File

@ -0,0 +1,365 @@
##################################################################################
# Goliath Tools CURL Module
##################################################################################
# Copyright (c) 2013-2021 Artica Soluciones Tecnologicas S.L
# This code is not free or OpenSource. Please don't redistribute.
##################################################################################
package PandoraFMS::Goliat::GoliatCURL;
use PandoraFMS::Goliat::GoliatTools;
use strict;
use warnings;
use Data::Dumper;
use PandoraFMS::DB;
use IO::Socket::INET6;
use URI::Escape;
use Time::Local;
use Time::HiRes qw ( gettimeofday );
# Japanese encoding support
use Encode::Guess qw/euc-jp shiftjis iso-2022-jp/;
require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
g_http_task
@task_requests
@task_reqsec
@task_fails
@task_time
@task_end
@task_sessions
@task_ssec
@task_get_string
@task_get_content
@task_session_fails
);
our @task_requests;
our @task_reqsec;
our @task_fails ;
our @task_time;
our @task_end;
our @task_sessions;
our @task_ssec;
our @task_get_string;
our @task_get_content;
our @task_session_fails;
our $goliat_abort;
# Returns a string than can be safely used as a command line parameter for CURL
sub safe_param ($) {
my $string = shift;
$string =~ s/'/"/g;
return "'" . $string . "'";
}
sub g_http_task {
my ( $config, $thread_id, @work_list ) = @_;
my ( $ax, $bx, $cx ); # used in FOR loop
my ( $ttime1, $ttime2, $ttime_tot );
my $resp; # HTTP Response
my $total_requests = 0;
my $total_valid_requests = 0;
my $total_invalid_request = 0;
my $cookie_file = "/tmp/gtc_".$thread_id."_".g_trash_ascii (3);
my $check_string = 1;
my $get_string = "";
my $get_content = "";
my $get_content_advanced = "";
my $timeout = 10;
#my $ua = new LWP::UserAgent;
$task_requests [$thread_id] = 0 ;
$task_sessions [$thread_id] = 0 ;
$task_reqsec[$thread_id] = 0;
$task_fails[$thread_id] = 0;
$task_session_fails[$thread_id] = 0;
$task_ssec[$thread_id] = 0;
$task_end[$thread_id] = 0;
$task_time[$thread_id] = 0;
$task_get_string[$thread_id] = "";
$task_get_content[$thread_id] = "";
# Set command line options for CURL
my $curl_opts;
# Follow redirects
$curl_opts .= " --location-trusted";
# User agent
if ($config->{"agent"} ne '') {
$curl_opts .= " -A " . safe_param($config->{"agent"})
}
# Prevent pages from being cached
$curl_opts .= " -H 'Pragma: no-cache'";
# Timeout
if (defined ($config->{"timeout"}) && $config->{"timeout"} > 0) {
$timeout = $config->{"timeout"};
}
# Maximum file size
if (defined($config->{"maxsize"}) && $config->{"maxsize"} > 0) {
$curl_opts .= " --max-filesize " . $config->{"maxsize"};
}
# Disable SSL certificate host verification
$curl_opts .= " -k";
# Proxy
if ($config->{'proxy'} ne ""){
$curl_opts .= " -x " . safe_param($config->{'proxy'});
}
# Proxy HTTP authentication
if ($config->{'auth_user'} ne "") {
$curl_opts .= " --proxy-anyauth -U " . safe_param($config->{'auth_user'} . ':' . $config->{'auth_pass'});
}
# Delete existing cookies
my $cookie_carry_on = 0;
if ( -e $cookie_file){
unlink ($cookie_file);
}
$ttime1 = Time::HiRes::gettimeofday();
for ($ax = 0; $ax != $config->{'retries'}; $ax++){
for ($bx = 0; $bx < $config->{"work_items"}; $bx++){
if ($config->{'con_delay'} > 0){
sleep ($config->{'con_delay'});
}
$total_requests++;
# Start to count!
$check_string = 1;
# Prepare parameters
my $task_curl_opts = $curl_opts;
my $params = "";
$cx = 0;
while (defined($work_list[$bx]->{'variable_name'}[$cx])){
if ($cx > 0){
$params = $params."&";
}
$params = $params . $work_list[$bx]->{'variable_name'}[$cx] . "=" . uri_escape($work_list[$bx]->{'variable_value'}[$cx]);
$cx++;
}
# Cookie carry on
if (defined ($work_list[$bx]->{'cookie'}) && $work_list[$bx]->{'cookie'} == 1){
$cookie_carry_on = 1;
}
if ($cookie_carry_on == 1) {
$task_curl_opts .= " -c " . safe_param ($cookie_file);
$task_curl_opts .= " -b " . safe_param ($cookie_file);
}
# HTTP authentication
if ($work_list[$bx]->{'http_auth_user'} ne "" && $work_list[$bx]->{'http_auth_pass'} ne "") {
if($config->{'http_check_type'} == 0){
$task_curl_opts .= " --anyauth -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 1) {
$task_curl_opts .= " --ntlm -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 2) {
$task_curl_opts .= " --digest -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
if ($config->{'http_check_type'} == 3) {
$task_curl_opts .= " --basic -u " . safe_param($work_list[$bx]->{'http_auth_user'} . ':' . $work_list[$bx]->{'http_auth_pass'});
}
}
# GET
if ($work_list[$bx]->{'type'} eq "GET"){
$task_curl_opts .= " -H 'Accept: text/html'";
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . $params;
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
# POST
} elsif ($work_list[$bx]->{'type'} eq "POST") {
$task_curl_opts .= " -d " . safe_param($params);
$task_curl_opts .= " -H 'Content-type: application/x-www-form-urlencoded'";
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
# HEAD
} else {
$task_curl_opts .= " -I";
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . uri_escape($params);
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = curl ($config->{"plugin_exec"}, $timeout, $task_curl_opts, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'}, $config->{"moduleId"}, $config->{"dbh"});
}
# Get string ?
if (defined($work_list[$bx]->{'get_string'})) {
my $temp = $work_list[$bx]->{'get_string'};
if ($resp =~ m/($temp)/) {
$task_get_string[$thread_id] = $1;
}
}
# Get response ?
if ($work_list[$bx]->{'get_content_advanced'} ne "") {
my $temp = $work_list[$bx]->{'get_content_advanced'};
if ($resp =~ m/$temp/) {
$task_get_content[$thread_id] = $1 if defined ($1);
}
} elsif ($work_list[$bx]->{'get_content'} ne "") {
my $temp = $work_list[$bx]->{'get_content'};
if ($resp =~ m/($temp)/) {
$task_get_content[$thread_id] = $1;
}
} else {
$task_get_content[$thread_id] = $resp;
}
# Resource bashing
#if ((defined($work_list[$bx]->{'get_resources'})) && ($work_list[$bx]->{'get_resources'} == 1)){
# $total_requests = g_get_all_links ($config, $ua, $resp, $total_requests, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
#}
# CHECKSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checkstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checkstring'}[$cx];
my $as_string = $resp;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string =~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# CHECKNOTSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checknotstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checknotstring'}[$cx];
my $as_string = $resp;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string !~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# End just now by pressing CTRL-C or Kill Signal !
#if ($goliat_abort == 1){
#$ax = $config->{'retries'};
#$bx = $config->{'items'};
#goto END_LOOP;
#}
} #main work_detail loop
$ttime2 = Time::HiRes::gettimeofday();
$ttime_tot = $ttime2 - $ttime1; # Total time for this task
$task_time[$thread_id] = $ttime_tot;
$task_requests [$thread_id] = $total_requests;
if ($ttime_tot > 0 ){
$task_reqsec[$thread_id] = $total_requests / $ttime_tot;
} else {
$task_reqsec[$thread_id] = $total_requests;
}
$task_fails[$thread_id] = $total_invalid_request;
if ($check_string == 0){
$task_session_fails[$thread_id]++
}
$task_sessions [$thread_id]++;
if ($task_sessions [$thread_id] > 0 ){
$task_ssec[$thread_id] = $ttime_tot / $task_sessions [$thread_id];
} else {
$task_ssec[$thread_id] = $task_sessions[$thread_id];
}
sleep $config->{'ses_delay'};
}
END_LOOP:
if ( -f $cookie_file){
unlink ($cookie_file);
}
$task_end[$thread_id] = 1;
}
# Call CURL and return its output.
sub curl {
my ($exec, $timeout, $curl_opts, $url, $headers, $debug, $moduleId, $dbh) = @_;
while (my ($header, $value) = each %{$headers}) {
$curl_opts .= " -H " . safe_param($header . ':' . $value);
}
my $cmd = "curl $curl_opts " . safe_param($url);
my $response = `"$exec" $timeout $cmd 2>/dev/null`;
# Curl command stored for live debugging feature.
set_update_agentmodule ($dbh, $moduleId, { 'debug_content' => $cmd }) if defined($dbh);
return $response if ($debug eq '');
# Debug
if (open (DEBUG, '>>', $debug . '.req')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $cmd;
print "\n";
close (DEBUG);
}
if (open (DEBUG, '>>', $debug . '.res')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $response;
print "\n";
close (DEBUG);
}
return $response;
}
# End of function declaration
# End of defined Code
1;
__END__

View File

@ -0,0 +1,265 @@
##########################################################################
# Goliat Config package
##########################################################################
# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L
# This code is not free or OpenSource. Please don't redistribute.
##########################################################################
package PandoraFMS::Goliat::GoliatConfig;
use strict;
use warnings;
use PandoraFMS::Tools;
use PandoraFMS::Goliat::GoliatTools;
require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw( g_help_screen
g_init
g_load_config );
my $g_version = "1.0";
my $g_build = "110929";
our $VERSION = $g_version." ".$g_build;
sub g_load_config {
my ( $config , $work_list )= @_ ;
my $archivo_cfg = $config->{'config_file'};
my $buffer_line;
my $task_block = 0;
my $commit_block = 0;
my $task_url = "";
my $task_cookie = 0;
my $task_resources = 1;
my $task_type = "";
my $task_headers = {};
my $task_debug = "";
my $http_auth_user = "";
my $http_auth_pass = "";
my $http_auth_realm = "";
my $http_auth_serverport = "";
my $get_string = "";
my $get_content = "";
my $get_content_advanced = "";
my @task_variable_name;
my @task_variable_value;
my @task_check_string;
my @task_check_not_string;
my $parametro;
my $temp1;
# Default options
$config->{'con_delay'} =0;
$config->{'ses_delay'} =0;
if (!defined($config->{'agent'})){
$config->{'agent'}="PandoraFMS/Goliat 4.0; Linux)";
}
if (!defined($config->{'proxy'})){
$config->{'proxy'}="";
}
if (!defined($config->{'retries'})){
$config->{'retries'} = 1;
}
if ((!is_numeric($config->{'retries'})) || ($config->{'retries'} == 0)){
$config->{'retries'} = 1;
}
$config->{'refresh'} = "5";
$config->{"max_depth"} = 25;
$config->{'log_file'}="/var/log/pandora/pandora_goliat.log";
$config->{'log_output'} = 0;
# Collect items from config file and put in an array
open (CFG, "< $archivo_cfg");
while (<CFG>){
$buffer_line = $_;
if ($buffer_line =~ /^[a-zA-Z]/){ # begins with letters
$parametro = $buffer_line;
} else {
$parametro = "";
}
# Need to commit block ??
if (($commit_block == 1) && ($task_block == 1)) {
my %work_item;
$work_item{'url'} = $task_url;
$work_item{'cookie'} = $task_cookie;
$work_item{'type'} = $task_type;
$work_item{'get_resources'} = $task_resources;
$work_item{'get_string'} = $get_string;
$work_item{'get_content'} = $get_content;
$work_item{'get_content_advanced'} = $get_content_advanced;
$work_item{'http_auth_user'} = $http_auth_user;
$work_item{'http_auth_pass'} = $http_auth_pass;
$work_item{'http_auth_realm'} = $http_auth_realm;
$work_item{'http_auth_serverport'} = $http_auth_serverport;
$work_item{'headers'} = $task_headers;
$work_item{'debug'} = $task_debug;
my $ax=0;
while ($#task_check_string >= 0){
$temp1 = pop (@task_check_string);
$work_item{'checkstring'}[$ax] = $temp1;
$ax++;
}
$ax=0;
while ($#task_check_not_string >= 0){
$temp1 = pop (@task_check_not_string);
$work_item{'checknotstring'}[$ax] = $temp1;
$ax++;
}
$ax=0;
while ($#task_variable_name >= 0){
$temp1 = pop (@task_variable_name);
$work_item{'variable_name'}[$ax] = $temp1;
$ax++;
}
$ax=0;
while ($#task_variable_value >= 0){
$temp1 = pop (@task_variable_value);
$work_item{'variable_value'}[$ax] = $temp1;
$ax++;
}
push @{$work_list}, \%work_item;
$commit_block = 0;
$task_block = 0;
$task_url = "";
$task_cookie = 0;
$task_resources = 0;
$task_type = "";
$task_headers = {};
$task_debug = "";
$config->{"work_items"}++;
$commit_block = 0;
$task_block = 0;
$http_auth_user = "";
$http_auth_pass = "";
$http_auth_realm = "";
$get_string = "";
$get_content = "";
$get_content_advanced = "";
}
# ~~~~~~~~~~~~~~
# Main setup items
# ~~~~~~~~~~~~~~
if ($parametro =~ m/^task_begin/i) {
$task_block = 1;
}
elsif ($parametro =~ m/^task_end/i) {
$commit_block = 1;
}
elsif ($parametro =~ m/^ses_delay\s(.*)/i) {
$config->{'ses_delay'} = $1;
}
elsif ($parametro =~ m/^con_delay\s(.*)/i) {
$config->{'con_delay'} = $1;
}
elsif ($parametro =~ m/^agent\s(.*)/i) {
$config->{'agent'} = $1;
}
elsif ($parametro =~ m/^proxy\s(.*)/i) {
$config->{'proxy'} = $1;
}
elsif ($parametro =~ m/^max_depth\s(.*)/i) {
$config->{'max_depth'} = $1;
}
elsif ($parametro =~ m/^log_file\s(.*)/i) {
$config->{"log_file"} = $1;
}
elsif ($parametro =~ m/^log_output\s(.*)/i) {
$config->{"log_output"} = $1;
}
elsif ($parametro =~ m/^log_http\s(.*)/i) {
$config->{"log_http"} = $1;
}
elsif ($parametro =~ m/^retries\s(.*)/i) {
$config->{"retries"} = $1;
}
# ~~~~~~~~~~~~~~
# Task items
# ~~~~~~~~~~~~~~
elsif ($parametro =~ m/^variable_name\s(.*)/i) {
push (@task_variable_name, $1);
}
elsif ($parametro =~ m/^variable_value\s(.*)/i) {
push (@task_variable_value, $1);
}
elsif ($parametro =~ m/^check_string\s(.*)/i) {
push (@task_check_string, $1);
}
elsif ($parametro =~ m/^check_not_string\s(.*)/i) {
push (@task_check_not_string, $1);
}
elsif ($parametro =~ m/^get\s(.*)/i) {
$task_type = "GET";
$task_url = $1;
}
elsif ($parametro =~ m/^post\s(.*)/i) {
$task_type = "POST";
$task_url = $1;
}
elsif ($parametro =~ m/^head\s(.*)/i) {
$task_type = "HEAD";
$task_url = $1;
}
# New in 4.0 version
elsif ($parametro =~ m/^get_string\s(.*)/i) {
$get_string = $1;
}
elsif ($parametro =~ m/^get_content\s(.*)/i) {
$get_content = $1;
}
elsif ($parametro =~ m/^get_content_advanced\s(.*)/i) {
$get_content_advanced = $1;
}
elsif ($parametro =~ m/^http_auth_user\s(.*)/i) {
$http_auth_user = $1;
}
elsif ($parametro =~ m/^http_auth_pass\s(.*)/i) {
$http_auth_pass = $1;
}
elsif ($parametro =~ m/^http_auth_realm\s(.*)/i) {
$http_auth_realm = $1;
}
elsif ($parametro =~ m/^http_auth_serverport\s(.*)/i) {
$http_auth_serverport = $1;
}
elsif ($parametro =~ m/^cookie\s(.*)/i) {
if ($1 =~ m/1/i){
$task_cookie = 1;
} else {
$task_cookie = 0;
}
}
elsif ($parametro =~ m/^resource\s(.*)/i) {
if ($1 =~ m/1/i){
$task_resources = 1;
} else {
$task_resources = 0;
}
}
# New in 5.0 version
elsif ($parametro =~ m/^header\s+(\S+)\s(.*)/i) {
$task_headers->{$1} = $2;
}
elsif ($parametro =~ m/^debug\s+(.*)/i) {
$task_debug = $1;
}
}
close (CFG);
}
# End of function declaration
# End of defined Code
1;
__END__

View File

@ -0,0 +1,478 @@
##################################################################################
# Goliath Tools LWP Module
##################################################################################
# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L
# This code is not free or OpenSource. Please don't redistribute.
##################################################################################
package PandoraFMS::Goliat::GoliatLWP;
use PandoraFMS::Goliat::GoliatTools;
use strict;
use warnings;
use Data::Dumper;
use IO::Socket::INET6;
use LWP::UserAgent;
use LWP::ConnCache;
use HTTP::Request::Common;
use HTTP::Response;
use HTML::TreeBuilder;
use HTML::Element;
use HTTP::Cookies;
use URI::URL;
use Time::Local;
use Time::HiRes qw ( gettimeofday );
# For IPv6 support in Net::HTTP.
BEGIN {
$Net::HTTP::SOCKET_CLASS = 'IO::Socket::INET6';
require Net::HTTP;
}
# Japanese encoding support
use Encode::Guess qw/euc-jp shiftjis iso-2022-jp/;
require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
g_http_task
@task_requests
@task_reqsec
@task_fails
@task_time
@task_end
@task_sessions
@task_ssec
@task_get_string
@task_get_content
@task_session_fails
);
our @task_requests;
our @task_reqsec;
our @task_fails;
our @task_time;
our @task_end;
our @task_sessions;
our @task_ssec;
our @task_get_string;
our @task_get_content;
our @task_session_fails;
our $goliat_abort;
sub parse_html ($;$)
{
my $p = $_[1];
$p = _new_tree_maker() unless $p;
$p->parse($_[0]);
}
sub parse_htmlfile ($;$)
{
my($file, $p) = @_;
local(*HTML);
open(HTML, $file) or return undef;
$p = _new_tree_maker() unless $p;
$p->parse_file(\*HTML);
}
sub _new_tree_maker
{
my $p = HTML::TreeBuilder->new(implicit_tags => 1,
ignore_unknown => 1,
ignore_text => 0,
'warn' => 0,
);
$p->strict_comment(1);
$p;
}
sub g_http_task {
my ( $config, $thread_id, @work_list ) = @_;
my ( $ax, $bx, $cx ); # used in FOR loop
my ( $ttime1, $ttime2, $ttime_tot );
my $resp; # HTTP Response
my $total_requests = 0;
my $total_valid_requests = 0;
my $total_invalid_request = 0;
my $cookie_file = "/tmp/gtc_".$thread_id."_".g_trash_ascii (3);
my $check_string = 1;
my $get_string = "";
my $get_content = "";
my $get_content_advanced = "";
my $ua = new LWP::UserAgent;
$task_requests [$thread_id] = 0 ;
$task_sessions [$thread_id] = 0 ;
$task_reqsec[$thread_id] = 0;
$task_fails[$thread_id] = 0;
$task_session_fails[$thread_id] = 0;
$task_ssec[$thread_id] = 0;
$task_end[$thread_id] = 0;
$task_time[$thread_id] = 0;
$task_get_string[$thread_id] = "";
$task_get_content[$thread_id] = "";
$ua->agent($config->{"agent"});
$ua->protocols_allowed( ['http', 'https'] );
$ua->default_headers->push_header('pragma' => "no-cache");
$ua->timeout ($config->{"timeout"});
$ua->max_size($config->{"maxsize"});
$ua->use_alarm($config->{"alarm"});
# Disable SSL certificate host verification
if ($ua->can ('ssl_opts')) {
$ua->ssl_opts("verify_hostname" => 0);
}
# Set proxy
if ($config->{'proxy'} ne ""){
$ua->proxy(['http','https'], $config->{'proxy'});
}
# Set HTTP Proxy auth
if ($config->{'auth_user'} ne "") {
$ua->credentials(
$config->{'auth_server'},
$config->{'auth_realm'},
$config->{'auth_user'} => $config->{'auth_pass'} );
}
if ( -e $cookie_file){
unlink ($cookie_file);
}
my $cookies = HTTP::Cookies->new ('file' => $cookie_file, 'autosave' => '0');
$ttime1 = Time::HiRes::gettimeofday();
for ($ax = 0; $ax != $config->{'retries'}; $ax++){
for ($bx = 0; $bx < $config->{"work_items"}; $bx++){
if ($config->{'con_delay'} > 0){
sleep ($config->{'con_delay'});
}
$total_requests++;
# Start to count!
$check_string = 1;
# Prepare parameters
my $params = "";
$cx = 0;
while (defined($work_list[$bx]->{'variable_name'}[$cx])){
if ($cx > 0){
$params = $params."&";
}
$params = $params . $work_list[$bx]->{'variable_name'}[$cx] . "=" . $work_list[$bx]->{'variable_value'}[$cx];
$cx++;
}
if ( (defined($work_list[$bx]->{'http_auth_realm'})) && (defined($work_list[$bx]->{'http_auth_serverport'}))&& (defined($work_list[$bx]->{'http_auth_user'})) && (defined($work_list[$bx]->{'http_auth_pass'}))) {
if ($work_list[$bx]->{'http_auth_realm'} ne "") {
$ua->credentials(
$work_list[$bx]->{'http_auth_serverport'},
$work_list[$bx]->{'http_auth_realm'},
$work_list[$bx]->{'http_auth_user'} => $work_list[$bx]->{'http_auth_pass'}
);
}
}
# GET
if ($work_list[$bx]->{'type'} eq "GET"){
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . $params;
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = g_get_page ( $ua, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
# POST
} elsif ($work_list[$bx]->{'type'} eq "POST") {
$resp = g_post_page ( $ua, $work_list[$bx]->{'url'}, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
# HEAD
} else {
if ($cx > 0){
$params = $work_list[$bx]->{'url'} . "?" . $params;
} else {
$params = $work_list[$bx]->{'url'};
}
$resp = g_head_page ( $ua, $params, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
}
# Check for errors.
if ($resp->code() == 500) {
$total_invalid_request++;
$bx = $config->{"work_items"};
$check_string=0;
last;
}
# Get string ?
if (defined($work_list[$bx]->{'get_string'})) {
my $as_string = $resp->as_string;
my $temp = $work_list[$bx]->{'get_string'};
if ($as_string =~ m/($temp)/) {
$task_get_string[$thread_id] = $1;
}
}
# Get response ?
if ($work_list[$bx]->{'get_content_advanced'} ne "") {
my $content = $resp->decoded_content;
my $temp = $work_list[$bx]->{'get_content_advanced'};
if ($content =~ m/$temp/) {
$task_get_content[$thread_id] = $1 if defined ($1);
}
} elsif ($work_list[$bx]->{'get_content'} ne "") {
my $content = $resp->decoded_content;
my $temp = $work_list[$bx]->{'get_content'};
if ($content =~ m/($temp)/) {
$task_get_content[$thread_id] = $1;
}
}
# Resource bashing
if ((defined($work_list[$bx]->{'get_resources'})) && ($work_list[$bx]->{'get_resources'} == 1)){
$total_requests = g_get_all_links ($config, $ua, $resp, $total_requests, $work_list[$bx]->{'url'}, $work_list[$bx]->{'headers'}, $work_list[$bx]->{'debug'});
}
# CHECKSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checkstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checkstring'}[$cx];
my $as_string = $resp->as_string;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string =~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# CHECKNOTSTRING check
$cx = 0;
while (defined($work_list[$bx]->{'checknotstring'}[$cx])) {
my $match_string = $work_list[$bx]->{'checknotstring'}[$cx];
my $as_string = $resp->as_string;
my $guess = Encode::Guess::guess_encoding($as_string);
if (ref $guess) {
$as_string = $guess->decode($as_string);
}
unless (utf8::is_utf8($match_string)) {
utf8::decode($match_string);
}
if ( $as_string !~ m/$match_string/i ){
$total_valid_requests++;
} else {
$total_invalid_request++;
$bx = $config->{"work_items"}; # Abort session remaining request
$check_string=0;
}
$cx++;
}
# Cookie carry on
if (defined ($work_list[$bx]->{'cookie'}) && $work_list[$bx]->{'cookie'} == 1){
$cookies->extract_cookies($resp);
$ua->cookie_jar($cookies);
}
# End just now by pressing CTRL-C or Kill Signal !
#if ($goliat_abort == 1){
#$ax = $config->{'retries'};
#$bx = $config->{'items'};
#goto END_LOOP;
#}
} #main work_detail loop
$ttime2 = Time::HiRes::gettimeofday();
$ttime_tot = $ttime2 - $ttime1; # Total time for this task
$task_time[$thread_id] = $ttime_tot;
$task_requests [$thread_id] = $total_requests;
if ($ttime_tot > 0 ){
$task_reqsec[$thread_id] = $total_requests / $ttime_tot;
} else {
$task_reqsec[$thread_id] = $total_requests;
}
$task_fails[$thread_id] = $total_invalid_request;
if ($check_string == 0){
$task_session_fails[$thread_id]++
}
$task_sessions [$thread_id]++;
if ($task_sessions [$thread_id] > 0 ){
$task_ssec[$thread_id] = $ttime_tot / $task_sessions [$thread_id];
} else {
$task_ssec[$thread_id] = $task_sessions[$thread_id];
}
sleep $config->{'ses_delay'};
}
END_LOOP:
$cookies->clear;
if ( -f $cookie_file){
unlink ($cookie_file);
}
$task_end[$thread_id] = 1;
}
sub g_get_all_links {
my ($config, $ua, $response, $counter, $myurl, $headers, $debug) = @_;
my $html;
if ($response->is_success) {
$html = $response->content;
} else {
return $counter;
}
# Beware this funcion, needs to be destroyed after use it !!!
my $parsed_html = parse_html($html);
#$ua->conn_cache(LWP::ConnCache->new());
my @url_list;
my $url = "";
my $link;
my $full_url;
for (@{ $parsed_html->extract_links( ) }) {
$link=$_->[0];
if (($link =~ m/.png/i) || ($link =~ m/.gif/i) || ($link =~ m/.htm/i) ||
($link =~ m/.html/i) || ($link =~ m/.pdf/i) || ($link =~ m/.jpg/i)
|| ($link =~ m/.ico/i)){
$url = new URI::URL $link;
$full_url = $url->abs($myurl);
@url_list = $full_url;
}
}
$parsed_html->delete;
my $ax = 0;
while ($full_url = pop(@url_list)) {
g_get_page ($ua, $full_url, $headers, $debug);
$counter++;
$ax++;
if ($ax > $config->{"max_depth"}){
return $counter;
}
}
return $counter;
}
sub g_get_page {
my $ua = $_[0];
my $url = $_[1];
my $headers = $_[2];
my $debug = $_[3];
my $req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html');
while (my ($header, $value) = each %{$headers}) {
$req->header($header => $value);
}
my $response = $ua->request($req);
return $response if ($debug eq '');
# Debug
if (open (DEBUG, '>>', $debug . '.req')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $req->as_string ();
print "\n";
close (DEBUG);
}
if (open (DEBUG, '>>', $debug . '.res')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $response->as_string ();
print "\n";
close (DEBUG);
}
return $response;
}
sub g_head_page {
my $ua = $_[0];
my $url = $_[1];
my $headers = $_[2];
my $debug = $_[3];
my $req = HTTP::Request->new(HEAD => $url);
$req->header('Accept' => 'text/html');
while (my ($header, $value) = each %{$headers}) {
$req->header($header => $value);
}
my $response = $ua->request($req);
return $response if ($debug eq '');
# Debug
if (open (DEBUG, '>>', $debug . '.req')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $req->as_string ();
print "\n";
close (DEBUG);
}
if (open (DEBUG, '>>', $debug . '.res')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $response->as_string ();
print "\n";
close (DEBUG);
}
return $response;
}
sub g_post_page {
my $ua = $_[0];
my $url = $_[1];
my $content = $_[2];
my $headers = $_[3];
my $debug = $_[4];
my $req = HTTP::Request->new(POST => $url);
$req->content_type('application/x-www-form-urlencoded');
$req->content ($content);
while (my ($header, $value) = each %{$headers}) {
$req->header($header => $value);
}
my $response = $ua->request($req);
return $response if ($debug eq '');
# Debug
if (open (DEBUG, '>>', $debug . '.req')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $req->as_string ();
print "\n";
close (DEBUG);
}
if (open (DEBUG, '>>', $debug . '.res')) {
print DEBUG "[Goliat debug " . time () . "]\n";
print DEBUG $response->as_string ();
print "\n";
close (DEBUG);
}
return $response;
}
# End of function declaration
# End of defined Code
1;
__END__

View File

@ -0,0 +1,222 @@
###############################################################################
# Goliath Tools Module
###############################################################################
# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L
# This code is not free or OpenSource. Please don't redistribute.
###############################################################################
package PandoraFMS::Goliat::GoliatTools;
use 5.008004;
use strict;
use warnings;
use integer;
require Exporter;
our @ISA = ("Exporter");
our %EXPORT_TAGS = ( 'all' => [ qw() ] );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
our @EXPORT = qw(
g_clean_string
g_clean_string_unicode
g_random_string
g_trash_ascii
g_trash_unicode
g_unicode );
# Delaracion de funciones publicas
##############################################################################
# clean_string (string) - Purge a string for any forbidden characters (esc, etc)
##############################################################################
sub g_clean_string {
my $micadena;
$micadena = $_[0];
$micadena =~ s/[^\-\:\;\.\,\_\s\a\*\=\(\)a-zA-Z0-9]/ /g;
$micadena =~ s/[\n\l\f]/ /g;
return $micadena;
}
##############################################################################
# limpia_cadena_unicode (string) - Purge a string for any unicode character
##############################################################################
sub g_clean_string_unicode {
my $micadena;
$micadena = $_[0];
$micadena =~ s/[%]/%%/g;
return $micadena;
}
#############################################################################
# Hex converter - Convert dec value in hex representation (00 - FF)
#############################################################################
sub g_decToHex { #return a 16bit (o uno de 8bit) hex value
my @hex = (0,1,2,3,4,5,6,7,8,9,"A","B","C","D","E","F");
my @dec = @_;
my $s3 = $hex[($dec[0]/4096)%16];
my $s2 = $hex[($dec[0]/256)%16];
my $s1 = $hex[($dec[0]/16)%16];
my $s0 = $hex[$dec[0]%16];
return "$s1$s0";
}
#############################################################################
# unicode - Generate unicode string (recursive)
#############################################################################
sub g_unicode {
my $config_word = $_[0];
my $config_depth = $_[1];
my $config_char="%";
if ($config_depth == 0) {
return $config_word;
}
my $a;
my $pos=0;
my $output="";
my $len;
for ($a=0;$a<$config_depth;$a++){
$len = length($config_word);
while ($pos < $len ) {
my $item;
$item = substr($config_word,$pos,1);
$output = $output.$config_char.decToHex(ord($item));
$pos++;
}
$config_word = $output;
}
return $output
}
#############################################################################
# trash - Generate "unicode" style trash string
#############################################################################
sub g_trash_unicode {
my $config_depth = $_[0];
my $config_char="%";
my $a;
my $output;
for ($a=0;$a<$config_depth;$a++){
$output = $output.$config_char.decToHex(int(rand(25)+97));
}
return $output
}
#############################################################################
# trash_ascii - Generate ASCII random strings
#############################################################################
sub g_trash_ascii {
my $config_depth = $_[0];
my $config_char="%";
my $a;
my $output;
for ($a=0;$a<$config_depth;$a++){
$output = $output.chr(int(rand(25)+97));
}
return $output
}
#############################################################################
# random_string (min, max, type) - Generate ASCII alphanumeric string,
# from min and max
#############################################################################
sub g_random_string {
my $config_min = $_[0];
my $config_max = $_[1];
my $config_type = $_[2]; # alphanumeric, alpha, numeric, lowalpha, highalpha
my $a;
my $output = "";
my @valid_chars;
my $rango;
# First fill list of valid chars (A-Z, a-z, 0-9)
if (($config_type eq "alphanumeric") || ($config_type eq "numeric")){
for ($a=48;$a<58;$a++){ # numeric
push @valid_chars, chr($a);
}
}
if (($config_type eq "alphanumeric") || ($config_type eq "alpha") ||
($config_type eq "highalpha") || ($config_type eq "lowalpha") ){
if (($config_type eq "alphanumeric") || ($config_type eq "highalpha") || ($config_type eq "alpha")){
for ($a=65;$a<91;$a++){ # alpha (CAPS)
push @valid_chars, chr($a);
}
}
if (($config_type eq "alphanumeric") || ($config_type eq "lowalpha") || ($config_type eq "alpha")){
for ($a=97;$a<123;$a++){ # alpha (low)
push @valid_chars, chr($a);
}
}
}
$rango = @valid_chars;
# Fill min. value
for ($a=0;$a<$config_min;$a++){
$output = $output.$valid_chars[(int(rand($rango)))];
}
# Fill to max;
if (($config_max - $config_min) != 0){
for ($a=0;$a<rand($config_max - $config_min +1)-1;$a++){
$output = $output.$valid_chars[(int(rand($rango)))];
}
}
return $output
}
1;
__END__
=head1 NAME
Goliath-Tools Library tools for Goliath application.
This is an internal module, does not use for independent apps.
=head1 SYNOPSIS
use GoliatTools;
=head1 DESCRIPTION
=head2 EXPORT
Pues no se que poner aqui :)
=head1 SEE ALSO
Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.
If you have a mailing list set up for your module, mention it here.
If you have a web site set up for your module, mention it here.
=head1 AUTHOR
slerena, E<lt>slerena@Egmail.com<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2005 by Sancho Lerena
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.4 or,
at your option, any later version of Perl 5 you may have available.
Licenced under GPL
=cut

View File

@ -0,0 +1,304 @@
package PandoraFMS::WebServer;
##########################################################################
# Pandora FMS Web Server.
# Pandora FMS. the Flexible Monitoring System. http://www.pandorafms.org
##########################################################################
# Copyright (c) 2007-2021 Artica Soluciones Tecnologicas S.L
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; version 2
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
##########################################################################
use strict;
use warnings;
use threads;
use threads::shared;
use Thread::Semaphore;
use File::Temp qw(tempfile);
use HTML::Entities;
use POSIX qw(strftime);
# Default lib dir for RPM and DEB packages
use lib '/usr/lib/perl5';
use PandoraFMS::Tools;
use PandoraFMS::DB;
use PandoraFMS::Core;
use PandoraFMS::ProducerConsumerServer;
use PandoraFMS::Goliat::GoliatTools;
use PandoraFMS::Goliat::GoliatConfig;
# Inherits from PandoraFMS::ProducerConsumerServer
our @ISA = qw(PandoraFMS::ProducerConsumerServer);
# Global variables
my @TaskQueue :shared;
my %PendingTasks :shared;
my $Sem :shared;
my $TaskSem :shared;
########################################################################################
# Web Server class constructor.
########################################################################################
sub new ($$;$) {
my ($class, $config, $dbh) = @_;
return undef unless defined ($config->{'webserver'}) and ($config->{'webserver'} == 1);
# Initialize semaphores and queues
@TaskQueue = ();
%PendingTasks = ();
$Sem = Thread::Semaphore->new;
$TaskSem = Thread::Semaphore->new (0);
# Call the constructor of the parent class
my $self = $class->SUPER::new($config, WEBSERVER, \&PandoraFMS::WebServer::data_producer, \&PandoraFMS::WebServer::data_consumer, $dbh);
bless $self, $class;
return $self;
}
###############################################################################
# Run.
###############################################################################
sub run ($) {
my $self = shift;
my $pa_config = $self->getConfig ();
print_message ($pa_config, " [*] Starting " . $pa_config->{'rb_product_name'} . " Web Server.", 1);
# Use Goliat with CURL
if ($pa_config->{'web_engine'} eq 'curl') {
require PandoraFMS::Goliat::GoliatCURL;
PandoraFMS::Goliat::GoliatCURL->import;
# Check for CURL binary
if (system ("curl -V >$DEVNULL 2>&1") >> 8 != 0) {
logger ($pa_config, ' [E] CURL binary not found. Install CURL or uncomment the web_engine configuration token to use LWP.', 1);
print_message ($pa_config, ' [E] CURL binary not found. Install CURL or uncomment the web_engine configuration token to use LWP.', 1);
return undef;
}
# Check for pandora_exec binary
if (system ("\"" . $pa_config->{'plugin_exec'} . "\" 10 echo >$DEVNULL 2>&1") >> 8 != 0) {
logger ($pa_config, ' [E] ' . $pa_config->{'plugin_exec'} . ' not found. Please install it or add it to the PATH.', 1);
print_message ($pa_config, ' [E] ' . $pa_config->{'plugin_exec'} . ' not found. Please install it or add it to the PATH.', 1);
return undef;
}
}
# Use LWP by default
else {
require PandoraFMS::Goliat::GoliatLWP;
PandoraFMS::Goliat::GoliatLWP->import;
if (! LWP::UserAgent->can('ssl_opts')) {
logger($pa_config, "LWP version $LWP::VERSION does not support SSL. Make sure version 6.0 or higher is installed.", 1);
print_message ($pa_config, " [W] LWP version $LWP::VERSION does not support SSL. Make sure version 6.0 or higher is installed.", 1);
}
}
$self->setNumThreads ($pa_config->{'web_threads'});
$self->SUPER::run (\@TaskQueue, \%PendingTasks, $Sem, $TaskSem);
}
###############################################################################
# Data producer.
###############################################################################
sub data_producer ($) {
my $self = shift;
my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
my @tasks;
my @rows;
if (pandora_is_master($pa_config) == 0) {
@rows = get_db_rows ($dbh, 'SELECT tagente_modulo.id_agente_modulo, tagente_modulo.flag, tagente_estado.current_interval + tagente_estado.last_execution_try AS time_left, last_execution_try
FROM tagente, tagente_modulo, tagente_estado
WHERE server_name = ?
AND tagente_modulo.id_agente = tagente.id_agente
AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND tagente.disabled = 0
AND tagente_modulo.id_modulo = 7
AND tagente_modulo.disabled = 0
AND (tagente_modulo.flag = 1 OR ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP()))
ORDER BY tagente_modulo.flag DESC, time_left ASC, last_execution_try ASC ', $pa_config->{'servername'});
} else {
@rows = get_db_rows ($dbh, 'SELECT DISTINCT(tagente_modulo.id_agente_modulo), tagente_modulo.flag, tagente_estado.current_interval + tagente_estado.last_execution_try AS time_left, last_execution_try
FROM tagente, tagente_modulo, tagente_estado, tserver
WHERE ((server_name = ?) OR (server_name = ANY(SELECT server_name FROM tserver WHERE status = 0 AND server_type = ?)))
AND tagente_modulo.id_agente = tagente.id_agente
AND tagente.disabled = 0
AND tagente_modulo.disabled = 0
AND tagente_modulo.id_modulo = 7
AND tagente_estado.id_agente_modulo = tagente_modulo.id_agente_modulo
AND ((tagente_estado.last_execution_try + tagente_estado.current_interval) < UNIX_TIMESTAMP() OR tagente_modulo.flag = 1 )
ORDER BY tagente_modulo.flag DESC, time_left ASC, last_execution_try ASC', $pa_config->{'servername'}, WEBSERVER);
}
foreach my $row (@rows) {
# Reset forced execution flag
if ($row->{'flag'} == 1) {
db_do ($dbh, 'UPDATE tagente_modulo SET flag = 0 WHERE id_agente_modulo = ?', $row->{'id_agente_modulo'});
}
push (@tasks, $row->{'id_agente_modulo'});
}
return @tasks;
}
###############################################################################
# Data consumer.
###############################################################################
sub data_consumer ($$) {
my ($self, $module_id) = @_;
my ($pa_config, $dbh) = ($self->getConfig (), $self->getDBH ());
our (@task_fails, @task_time, @task_ssec, @task_get_content); # Defined in GoliatLWP.pm and GoliatCURL.
# Retrieve module data
my $module = get_db_single_row ($dbh, 'SELECT * FROM tagente_modulo WHERE id_agente_modulo = ?', $module_id);
return unless defined ($module);
# Retrieve agent data
my $agent = get_db_single_row ($dbh, 'SELECT * FROM tagente WHERE id_agente = ?', $module->{'id_agente'});
return unless defined $agent;
# Save Goliat config to a temporary file
my ($fh, $temp_file) = tempfile();
return unless defined ($fh);
# Read the Goliat task
my $task = safe_output($module->{'plugin_parameter'});
# Delete any carriage returns
$task =~ s/\r//g;
# Agent and module macros
my %macros = (_agent_ => (defined ($agent)) ? $agent->{'alias'} : '',
_agentdescription_ => (defined ($agent)) ? $agent->{'comentarios'} : '',
_agentstatus_ => (defined ($agent)) ? get_agent_status ($pa_config, $dbh, $agent->{'id_agente'}) : '',
_address_ => (defined ($agent)) ? $agent->{'direccion'} : '',
_module_ => (defined ($module)) ? $module->{'nombre'} : '',
_modulegroup_ => (defined ($module)) ? (get_module_group_name ($dbh, $module->{'id_module_group'}) || '') : '',
_moduledescription_ => (defined ($module)) ? $module->{'descripcion'} : '',
_modulestatus_ => (defined ($module)) ? get_agentmodule_status($pa_config, $dbh, $module->{'id_agente_modulo'}) : '',
_moduletags_ => (defined ($module)) ? pandora_get_module_url_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '',
_id_agent_ => (defined ($module)) ? $module->{'id_agente'} : '',
_interval_ => (defined ($module) && $module->{'module_interval'} != 0) ? $module->{'module_interval'} : (defined ($agent)) ? $agent->{'intervalo'} : '',
_target_ip_ => (defined ($agent)) ? $agent->{'direccion'} : '',
_target_port_ => (defined ($module)) ? $module->{'tcp_port'} : '',
_policy_ => (defined ($module)) ? enterprise_hook('get_policy_name', [$dbh, $module->{'id_policy_module'}]) : '',
_plugin_parameters_ => (defined ($module)) ? $module->{'plugin_parameter'} : '',
_email_tag_ => (defined ($module)) ? pandora_get_module_email_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '',
_phone_tag_ => (defined ($module)) ? pandora_get_module_phone_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '',
_name_tag_ => (defined ($module)) ? pandora_get_module_tags ($pa_config, $dbh, $module->{'id_agente_modulo'}) : '',
);
$task = subst_alert_macros ($task, \%macros);
# Goliat has some trouble parsing conf files without the newlines
$fh->print ("\n\n" . $task . "\n\n");
close ($fh);
# Global vars needed by Goliat
my (%config, @work_list, $check_string);
# Goliat config defaults
$config{'verbosity'} = 1;
$config{'slave'} = 0;
$config{'port'} = 80;
$config{'log_file'} = "$DEVNULL";
$config{'log_output'} = 0;
$config{'log_http'} = 0;
$config{'work_items'} = 0;
$config{'config_file'} = $temp_file;
$config{'agent'} = safe_output($module->{'plugin_user'});
if ($module->{'max_retries'} != 0) {
$config{'retries'} = $module->{'max_retries'};
}
if ($module->{'max_timeout'} != 0) {
$config{'timeout'} = $module->{'max_timeout'};
} else {
$config{'timeout'} = $pa_config->{'web_timeout'};
}
$config{'proxy'} = $module->{'snmp_oid'};
$config{'auth_user'} = safe_output($module->{'tcp_send'});
$config{'auth_pass'} = safe_output($module->{'tcp_rcv'});
$config{'auth_server'} = $module->{'ip_target'};
$config{'auth_realm'} = $module->{'snmp_community'};
$config{'http_check_type'} = $module->{'tcp_port'};
$config{'moduleId'} = $module_id;
$config{'dbh'} = $dbh;
# Pandora FMS variables passed to Goliat.
$config{'plugin_exec'} = $pa_config->{'plugin_exec'};
eval {
# Load Goliat config
g_load_config(\%config, \@work_list);
# Run Goliat task
g_http_task (\%config, 0, @work_list);
};
if ($@) {
pandora_update_module_on_error ($pa_config, $module, $dbh);
unlink ($temp_file);
return;
}
unlink ($temp_file);
my $utimestamp = time ();
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", localtime($utimestamp));
# Get module type
my $module_type = get_db_value ($dbh, 'SELECT nombre FROM ttipo_modulo WHERE id_tipo = ?', $module->{'id_tipo_modulo'});
# Get data from Goliat
my $module_data;
{
no strict 'vars';
if ($module_type eq 'web_proc') {
$module_data = ($task_fails[0] == 0 && $task_get_content[0] ne "") ? 1 : 0;
}
elsif ($module_type eq 'web_data') {
$module_data = $task_ssec[0];
} elsif ($module_type eq 'web_server_status_code_string') {
my @resp_lines = split "\r\n", $task_get_content[0];
$module_data = $resp_lines[0];
} else {
$module_data = $task_get_content[0];
}
}
my %data = ("data" => $module_data);
pandora_process_module ($pa_config, \%data, undef, $module, $module_type, $timestamp, $utimestamp, $self->getServerID (), $dbh);
my $agent_os_version = get_db_value ($dbh, 'SELECT os_version FROM tagente WHERE id_agente = ?', $module->{'id_agente'});
if (! defined ($agent_os_version) || $agent_os_version eq '') {
$agent_os_version = $pa_config->{'servername'}.'_Web';
}
# Todo: Implement here
# 1. Detect if exists a module with the same name, but with type generic_string.
# 2. If not, create the module, get the id's
# 3. Insert data coming from $task_get_string in that module
pandora_update_agent ($pa_config, $timestamp, $module->{'id_agente'}, undef, undef, -1, $dbh);
}
1;
__END__