Merge branch 'ent-9771-discovery-2-0-sistema-de-extensiones-disco-para-el-discovery' into 'develop'

Ent 9771 discovery 2 0 sistema de extensiones disco para el discovery

See merge request artica/pandorafms!5603
This commit is contained in:
Daniel Rodriguez 2023-07-27 07:24:09 +00:00
commit 0c6877e7d2
26 changed files with 5766 additions and 65 deletions

View File

@ -1,5 +1,49 @@
START TRANSACTION;
CREATE TABLE IF NOT EXISTS `tdiscovery_apps` (
`id_app` int(10) auto_increment,
`short_name` varchar(250) NOT NULL DEFAULT '',
`name` varchar(250) NOT NULL DEFAULT '',
`section` varchar(250) NOT NULL DEFAULT 'custom',
`description` varchar(250) NOT NULL DEFAULT '',
`version` varchar(250) NOT NULL DEFAULT '',
PRIMARY KEY (`id_app`),
UNIQUE (`short_name`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_scripts` (
`id_app` int(10),
`macro` varchar(250) NOT NULL DEFAULT '',
`value` text NOT NULL DEFAULT '',
PRIMARY KEY (`id_app`, `macro`),
FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_executions` (
`id` int(10) unsigned NOT NULL auto_increment,
`id_app` int(10),
`execution` text NOT NULL DEFAULT '',
PRIMARY KEY (`id`, `id_app`),
FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_tasks_macros` (
`id_task` int(10) unsigned NOT NULL,
`macro` varchar(250) NOT NULL DEFAULT '',
`type` varchar(250) NOT NULL DEFAULT 'custom',
`value` text NOT NULL DEFAULT '',
`temp_conf` tinyint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id_task`, `macro`),
FOREIGN KEY (`id_task`) REFERENCES trecon_task(`id_rt`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
ALTER TABLE `trecon_task`
ADD COLUMN `id_app` int(10),
ADD COLUMN `setup_complete` tinyint unsigned NOT NULL DEFAULT 0,
ADD COLUMN `executions_timeout` int unsigned NOT NULL DEFAULT 60,
ADD FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE;
CREATE TABLE IF NOT EXISTS `tnetwork_explorer_filter` (
`id` INT NOT NULL,
`filter_name` VARCHAR(45) NULL,
@ -26,6 +70,7 @@ ALTER TABLE `tlayout_template`
ADD COLUMN `grid_color` VARCHAR(45) NOT NULL DEFAULT '#cccccc' AFTER `maintenance_mode`,
ADD COLUMN `grid_size` VARCHAR(45) NOT NULL DEFAULT '10' AFTER `grid_color`;
DELETE FROM tconfig WHERE token = 'refr';
INSERT INTO `tmodule_inventory` (`id_module_inventory`, `id_os`, `name`, `description`, `interpreter`, `data_format`, `code`, `block_mode`,`script_mode`) VALUES (37,2,'CPU','CPU','','Brand;Clock;Model','',0,2);

View File

@ -30,6 +30,7 @@
// Begin.
require_once 'include/config.php';
require_once 'include/functions_menu.php';
require_once $config['homedir'].'/godmode/wizards/ManageExtensions.class.php';
check_login();
@ -78,8 +79,89 @@ if ((bool) check_acl($config['id_user'], 0, 'AR') === true
}
if ((bool) check_acl($config['id_user'], 0, 'AW') === true) {
enterprise_hook('applications_menu');
enterprise_hook('cloud_menu');
// Applications.
$sub2 = [];
if (enterprise_installed() === true) {
$sub2['godmode/servers/discovery&wiz=app&mode=MicrosoftSQLServer']['text'] = __('Microsoft SQL Server');
$sub2['godmode/servers/discovery&wiz=app&mode=mysql']['text'] = __('Mysql');
$sub2['godmode/servers/discovery&wiz=app&mode=oracle']['text'] = __('Oracle');
$sub2['godmode/servers/discovery&wiz=app&mode=vmware']['text'] = __('VMware');
$sub2['godmode/servers/discovery&wiz=app&mode=SAP']['text'] = __('SAP');
$sub2['godmode/servers/discovery&wiz=app&mode=DB2']['text'] = __('DB2');
}
$extensions = ManageExtensions::getExtensionBySection('app');
if ($extensions !== false) {
foreach ($extensions as $key => $extension) {
$url = sprintf(
'godmode/servers/discovery&wiz=app&mode=%s',
$extension['short_name']
);
$sub2[$url]['text'] = __($extension['name']);
}
}
if ($extensions !== false || enterprise_installed() === true) {
$sub['godmode/servers/discovery&wiz=app']['text'] = __('Applications');
$sub['godmode/servers/discovery&wiz=app']['id'] = 'app';
$sub['godmode/servers/discovery&wiz=app']['type'] = 'direct';
$sub['godmode/servers/discovery&wiz=app']['subtype'] = 'nolink';
$sub['godmode/servers/discovery&wiz=app']['sub2'] = $sub2;
}
// Cloud.
$sub2 = [];
if (enterprise_installed() === true) {
$sub2['godmode/servers/discovery&wiz=cloud&mode=amazonws']['text'] = __('Amazon Web Services');
$sub2['godmode/servers/discovery&wiz=cloud&mode=azure']['text'] = __('Microsoft Azure');
$sub2['godmode/servers/discovery&wiz=cloud&mode=gcp']['text'] = __('Google Compute Platform');
}
$extensions = ManageExtensions::getExtensionBySection('cloud');
if ($extensions !== false) {
foreach ($extensions as $key => $extension) {
$url = sprintf(
'godmode/servers/discovery&wiz=cloud&mode=%s',
$extension['short_name']
);
$sub2[$url]['text'] = __($extension['name']);
}
}
if ($extensions !== false || enterprise_installed() === true) {
$sub['godmode/servers/discovery&wiz=cloud']['text'] = __('Cloud');
$sub['godmode/servers/discovery&wiz=cloud']['id'] = 'cloud';
$sub['godmode/servers/discovery&wiz=cloud']['type'] = 'direct';
$sub['godmode/servers/discovery&wiz=cloud']['subtype'] = 'nolink';
$sub['godmode/servers/discovery&wiz=cloud']['sub2'] = $sub2;
}
// Custom.
$sub2 = [];
$extensions = ManageExtensions::getExtensionBySection('custom');
if ($extensions !== false) {
foreach ($extensions as $key => $extension) {
$url = sprintf(
'godmode/servers/discovery&wiz=custom&mode=%s',
$extension['short_name']
);
$sub2[$url]['text'] = __($extension['name']);
}
$sub['godmode/servers/discovery&wiz=custom']['text'] = __('Custom');
$sub['godmode/servers/discovery&wiz=custom']['id'] = 'customExt';
$sub['godmode/servers/discovery&wiz=custom']['type'] = 'direct';
$sub['godmode/servers/discovery&wiz=custom']['subtype'] = 'nolink';
$sub['godmode/servers/discovery&wiz=custom']['sub2'] = $sub2;
}
if (check_acl($config['id_user'], 0, 'RW')
|| check_acl($config['id_user'], 0, 'RM')
|| check_acl($config['id_user'], 0, 'PM')
) {
$sub['godmode/servers/discovery&wiz=magextensions']['text'] = __('Manage disco packages');
$sub['godmode/servers/discovery&wiz=magextensions']['id'] = 'mextensions';
}
if ((bool) check_acl($config['id_user'], 0, 'RW') === true
@ -89,6 +171,7 @@ if ((bool) check_acl($config['id_user'], 0, 'AR') === true
enterprise_hook('console_task_menu');
}
}
}
// Add to menu.
$menu_godmode['discovery']['text'] = __('Discovery');

View File

@ -53,6 +53,12 @@ function get_wiz_class($str)
case 'deploymentCenter':
return 'DeploymentCenter';
case 'magextensions':
return 'ManageExtensions';
case 'custom':
return 'Custom';
default:
// Main, show header.
ui_print_standard_header(
@ -169,6 +175,12 @@ if ($classname_selected === null) {
$classname = basename($classpath, '.class.php');
$obj = new $classname();
if (method_exists($obj, 'isEmpty') === true) {
if ($obj->isEmpty() === true) {
continue;
}
}
$button = $obj->load();
if ($button === false) {

View File

@ -0,0 +1,221 @@
<?php
/**
* Applications wizard manager.
*
* @category Wizard
* @package Pandora FMS
* @subpackage Applications
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2021 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
require_once $config['homedir'].'/include/functions_users.php';
require_once $config['homedir'].'/include/class/ExtensionsDiscovery.class.php';
/**
* Implements Wizard to provide generic Applications wizard.
*/
class Applications extends Wizard
{
/**
* Sub-wizard to be launch (vmware,oracle...).
*
* @var string
*/
public $mode;
/**
* Constructor.
*
* @param integer $page Start page, by default 0.
* @param string $msg Default message to show to users.
* @param string $icon Target icon to be used.
* @param string $label Target label to be displayed.
*
* @return mixed
*/
public function __construct(
int $page=0,
string $msg='Default message. Not set.',
string $icon='images/wizard/applications.png',
string $label='Applications'
) {
$this->setBreadcrum([]);
$this->access = 'AW';
$this->task = [];
$this->msg = $msg;
$this->icon = $icon;
$this->class = $class_style;
$this->label = $label;
$this->page = $page;
$this->url = ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=app'
);
return $this;
}
/**
* Run wizard manager.
*
* @return mixed Returns null if wizard is ongoing. Result if done.
*/
public function run()
{
global $config;
// Load styles.
parent::run();
// Load current wiz. sub-styles.
ui_require_css_file(
'application',
ENTERPRISE_DIR.'/include/styles/wizards/'
);
$mode = get_parameter('mode', null);
// Load application wizards.
$enterprise_classes = glob(
$config['homedir'].'/'.ENTERPRISE_DIR.'/include/class/*.app.php'
);
$extensions = new ExtensionsDiscovery('app', $mode);
foreach ($enterprise_classes as $classpath) {
enterprise_include_once(
'include/class/'.basename($classpath)
);
}
switch ($mode) {
case 'DB2':
$classname_selected = 'DB2';
break;
case 'SAP':
$classname_selected = 'SAP';
break;
case 'vmware':
$classname_selected = 'VMware';
break;
case 'mysql':
$classname_selected = 'MySQL';
break;
case 'oracle':
$classname_selected = 'Oracle';
break;
case 'MicrosoftSQLServer':
$classname_selected = 'MicrosoftSQLServer';
break;
default:
$classname_selected = null;
break;
}
// Else: class not found pseudo exception.
if ($classname_selected !== null) {
$wiz = new $classname_selected($this->page);
$result = $wiz->run();
if (is_array($result) === true) {
return $result;
}
}
if ($classname_selected === null) {
if ($mode !== null) {
// Load extension if exist.
$extensions->run();
return;
}
// Load classes and print selector.
$wiz_data = [];
foreach ($enterprise_classes as $classpath) {
$classname = basename($classpath, '.app.php');
$obj = new $classname();
$wiz_data[] = $obj->load();
}
$wiz_data = array_merge($wiz_data, $extensions->loadExtensions());
$this->prepareBreadcrum(
[
[
'link' => ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery'
),
'label' => __('Discovery'),
],
[
'link' => ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=app'
),
'label' => __('Applications'),
'selected' => true,
],
]
);
// Header.
ui_print_page_header(
__('Applications'),
'',
false,
'',
true,
'',
false,
'',
GENERIC_SIZE_TEXT,
'',
$this->printHeader(true)
);
Wizard::printBigButtonsList($wiz_data);
echo '<div class="app_mssg"><i>*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'</i></div>';
}
return $result;
}
/**
* Check if section have extensions.
*
* @return boolean Return true if section is empty.
*/
public function isEmpty()
{
$extensions = new ExtensionsDiscovery('app');
$listExtensions = $extensions->getExtensionsApps();
if ($listExtensions > 0 || enterprise_installed() === true) {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,661 @@
<?php
/**
* Cloud wizard manager.
*
* @category Wizard
* @package Pandora FMS
* @subpackage Cloud
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2021 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
global $config;
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
require_once $config['homedir'].'/include/functions_users.php';
require_once $config['homedir'].'/include/class/CredentialStore.class.php';
/**
* Implements Wizard to provide generic Cloud wizard.
*/
class Cloud extends Wizard
{
/**
* Sub-wizard to be launch (vmware,oracle...).
*
* @var string
*/
public $mode;
/**
* Discovery task data.
*
* @var array.
*/
public $task;
/**
* General maxPages.
*
* @var integer
*/
public $maxPages;
/**
* Product string.
*
* @var string
*/
protected $product = '';
/**
* Credentials store identifier.
*
* @var string
*/
protected $keyIdentifier = null;
/**
* Credentials store product identifier.
*
* @var string
*/
protected $keyStoreType = null;
/**
* Constructor.
*
* @param integer $page Start page, by default 0.
* @param string $msg Default message to show to users.
* @param string $icon Target icon to be used.
* @param string $label Target label to be displayed.
*
* @return mixed
*/
public function __construct(
int $page=0,
string $msg='Default message. Not set.',
string $icon='images/wizard/cloud.png',
string $label='Cloud'
) {
$this->setBreadcrum([]);
$this->access = 'AW';
$this->task = [];
$this->msg = $msg;
$this->icon = $icon;
$this->label = $label;
$this->page = $page;
$this->url = ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=cloud'
);
return $this;
}
/**
* Run wizard manager.
*
* @return mixed Returns null if wizard is ongoing. Result if done.
*/
public function run()
{
global $config;
// Load styles.
parent::run();
// Load current wiz. sub-styles.
ui_require_css_file(
'cloud',
ENTERPRISE_DIR.'/include/styles/wizards/'
);
$mode = get_parameter('mode', null);
// Load cloud wizards.
$enterprise_classes = glob(
$config['homedir'].'/'.ENTERPRISE_DIR.'/include/class/*.cloud.php'
);
$extensions = new ExtensionsDiscovery('cloud', $mode);
foreach ($enterprise_classes as $classpath) {
enterprise_include_once(
'include/class/'.basename($classpath)
);
}
switch ($mode) {
case 'amazonws':
$classname_selected = 'Aws';
break;
case 'azure':
$classname_selected = 'Azure';
break;
case 'gcp':
$classname_selected = 'Google';
break;
default:
$classname_selected = null;
break;
}
// Else: class not found pseudo exception.
if ($classname_selected !== null) {
$wiz = new $classname_selected($this->page);
$result = $wiz->run();
if (is_array($result) === true) {
return $result;
}
}
if ($classname_selected === null) {
if ($mode !== null) {
// Load extension if exist.
$extensions->run();
return;
}
// Load classes and print selector.
$wiz_data = [];
foreach ($enterprise_classes as $classpath) {
$classname = basename($classpath, '.cloud.php');
$obj = new $classname();
$wiz_data[] = $obj->load();
}
$wiz_data = array_merge($wiz_data, $extensions->loadExtensions());
$this->prepareBreadcrum(
[
[
'link' => ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery'
),
'label' => __('Discovery'),
],
[
'link' => $this->url,
'label' => __('Cloud'),
'selected' => true,
],
],
true
);
// Header.
ui_print_page_header(
__('Cloud'),
'',
false,
'',
true,
'',
false,
'',
GENERIC_SIZE_TEXT,
'',
$this->printHeader(true)
);
Wizard::printBigButtonsList($wiz_data);
echo '<div class="app_mssg"><i>*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'</i></div>';
}
return $result;
}
/**
* Run credentials wizard.
*
* @return boolean True if credentials wizard is displayed and false if not.
*/
public function runCredentials()
{
global $config;
if ($this->status === false) {
$empty_account = true;
}
// Checks credentials. If check not passed. Show the form to fill it.
if ($this->checkCredentials()) {
return true;
}
// Add breadcrum and print header.
$this->prepareBreadcrum(
[
[
'link' => $this->url.'&credentials=1',
'label' => __('%s credentials', $this->product),
'selected' => true,
],
],
true
);
// Header.
ui_print_page_header(
__('%s credentials', $this->product),
'',
false,
$this->product.'_credentials_tab',
true,
'',
false,
'',
GENERIC_SIZE_TEXT,
'',
$this->printHeader(true)
);
if ($this->product === 'Aws') {
ui_print_warning_message(
__(
'If a task with the selected credentials is already running, it will be edited. To create a new one, another account from the credential store must be selected.'
)
);
}
if ($this->status === true) {
ui_print_success_message($this->msg);
} else if ($this->status === false) {
ui_print_error_message($this->msg);
}
if ($empty_account === true) {
ui_print_error_message($this->msg);
}
$link_to_cs = '';
if (check_acl($config['id_user'], 0, 'UM')) {
$link_to_cs = '<a class="ext_link" href="'.ui_get_full_url(
'index.php?sec=gmodules&sec2=godmode/groups/group_list&tab=credbox'
).'" >';
$link_to_cs .= __('Manage accounts').'</a>';
}
$this->getCredentials();
$this->printFormAsList(
[
'form' => [
'action' => $this->url,
'method' => 'POST',
'id' => 'form-credentials',
],
'inputs' => [
[
'label' => __('Cloud tool full path'),
'arguments' => [
'name' => 'cloud_util_path',
'value' => isset($config['cloud_util_path']) ? io_safe_output($config['cloud_util_path']) : '/usr/bin/pandora-cm-api',
'type' => 'text',
],
],
[
'label' => __('Account'),
'extra' => $link_to_cs,
'arguments' => [
'name' => 'account_identifier',
'type' => 'select',
'fields' => CredentialStore::getKeys($this->keyStoreType),
'selected' => $this->keyIdentifier,
'return' => true,
],
],
[
'arguments' => [
'name' => 'parse_credentials',
'value' => 1,
'type' => 'hidden',
'return' => true,
],
],
],
]
);
$buttons_form = $this->printInput(
[
'name' => 'submit',
'label' => __('Validate'),
'type' => 'submit',
'attributes' => [
'icon' => 'wand',
'form' => 'form-credentials',
],
'return' => true,
'width' => 'initial',
]
);
$buttons_form .= $this->printGoBackButton(
ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=cloud'
),
true
);
html_print_action_buttons($buttons_form);
return false;
}
/**
* Check credentials.
*
* @return boolean True if credentials are OK.
*/
public function checkCredentials()
{
global $config;
$pandora = io_safe_output($config['cloud_util_path']);
if (isset($pandora) === false) {
config_update_value('cloud_util_path', '/usr/bin/pandora-cm-api');
}
if ((bool) get_parameter('disconnect_account', false) === true) {
$this->status = null;
return false;
}
if ($this->keyIdentifier === null) {
// Ask user for available credentials.
$this->msg = __('Select a set of credentials from the list');
$this->status = null;
return false;
}
$credentials = $this->getCredentials($this->keyIdentifier);
if (empty($credentials['username']) === true
|| empty($credentials['password']) === true
|| isset($pandora) === false
|| is_executable($pandora) === false
) {
if (is_executable($pandora) === false) {
$this->msg = (__('Path %s is not executable.', $pandora));
$this->status = false;
} else {
$this->msg = __('Invalid username or password');
$this->status = false;
}
return false;
}
try {
$value = $this->executeCMCommand('--get availability');
} catch (Exception $e) {
$this->msg = $e->getMessage();
$this->status = false;
return false;
}
if ($value == '1') {
return true;
}
$this->status = false;
// Error message directly from pandora-cm-api.
$this->msg = str_replace('"', '', $value);
return false;
}
/**
* Handle the click on disconnect account link.
*
* @return void But it prints some info to user.
*/
protected function parseDisconnectAccount()
{
// Check if disconection account link is pressed.
if ((bool) get_parameter('disconnect_account') === false) {
return;
}
$ret = $this->setCredentials(null);
if ($ret) {
$this->msg = __('Account disconnected');
} else {
$this->msg = __('Failed disconnecting account');
}
$this->status = $ret;
$this->page = 0;
}
/**
* Build an array with Product credentials.
*
* @return array with credentials (pass and id).
*/
public function getCredentials()
{
return CredentialStore::getKey($this->keyIdentifier);
}
/**
* Set Product credentials.
*
* @param string|null $identifier Credential store identifier.
*
* @return boolean True if success.
*/
public function setCredentials($identifier)
{
if ($identifier === null) {
unset($this->keyIdentifier);
return true;
}
if (isset($identifier) === false) {
return false;
}
$all = CredentialStore::getKeys($this->type);
if (in_array($identifier, $all) === true) {
$this->keyIdentifier = $identifier;
return true;
}
return false;
}
/**
* Parse credentials form.
*
* @return void But it prints a message.
*/
protected function parseCredentials()
{
global $config;
if (!$this->keyIdentifier) {
$this->setCredentials(get_parameter('ki', null));
}
// Check if credentials form is submitted.
if ((bool) get_parameter('parse_credentials') === false) {
return;
}
$this->page = 0;
$ret = $this->setCredentials(
get_parameter('account_identifier')
);
$path = get_parameter('cloud_util_path');
$ret_path = config_update_value('cloud_util_path', $path);
if ($ret_path) {
$config['cloud_util_path'] = $path;
}
if ($ret && $ret_path) {
$this->msg = __('Credentials successfully updated');
} else {
$this->msg = __('Failed updating credentials process');
}
$this->status = ($ret && $ret_path);
}
/**
* This method must be implemented.
*
* Execute a pandora-cm-api request.
*
* @param string $command Command to execute.
*
* @return void But must return string STDOUT of executed command.
* @throws Exception If not implemented.
*/
protected function executeCMCommand($command)
{
throw new Exception('executeCMCommand must be implemented.');
}
/**
* Get a recon token value
*
* @param string $token The recon key to retrieve.
*
* @return string String with the value.
*/
protected function getConfigReconElement($token)
{
if ($this->reconConfig === false
|| isset($this->reconConfig[0][$token]) === false
) {
if (is_array($this->task) === true
&& isset($this->task[$token]) === true
) {
return $this->task[$token];
} else {
return '';
}
} else {
return $this->reconConfig[0][$token];
}
}
/**
* Print global inputs
*
* @param boolean $last True if is last element.
*
* @return array Array with all global inputs.
*/
protected function getGlobalInputs(bool $last=false)
{
$task_id = $this->task['id_rt'];
if (!$task_id) {
$task_id = $this->getConfigReconElement('id_rt');
}
return [
[
'arguments' => [
'name' => 'page',
'value' => ($this->page + 1),
'type' => 'hidden',
'return' => true,
],
],
[
'arguments' => [
'name' => 'submit',
'label' => ($last) ? __('Finish') : __('Next'),
'type' => 'submit',
'attributes' => 'class="sub '.(($last) ? 'wand' : 'next').'"',
'return' => true,
],
],
[
'arguments' => [
'name' => 'task',
'value' => $task_id,
'type' => 'hidden',
'return' => true,
],
],
[
'arguments' => [
'name' => 'parse_form',
'value' => 1,
'type' => 'hidden',
'return' => true,
],
],
];
}
/**
* Print required css in some points.
*
* @return string With js code.
*/
protected function cloudJS()
{
return '
function toggleCloudSubmenu(curr_elem, id_csm){
if (document.getElementsByName(curr_elem)[0].checked){
$("#li-"+id_csm).show();
} else {
$("#li-"+id_csm).hide();
}
};
';
}
/**
* Check if section have extensions.
*
* @return boolean Return true if section is empty.
*/
public function isEmpty()
{
$extensions = new ExtensionsDiscovery('cloud');
$listExtensions = $extensions->getExtensionsApps();
if ($listExtensions > 0 || enterprise_installed() === true) {
return false;
} else {
return true;
}
}
}

View File

@ -0,0 +1,160 @@
<?php
/**
* Custom wizard manager.
*
* @category Wizard
* @package Pandora FMS
* @subpackage Custom
* @version 1.0.0
* @license See below
*
* ______ ___ _______ _______ ________
* | __ \.-----.--.--.--| |.-----.----.-----. | ___| | | __|
* | __/| _ | | _ || _ | _| _ | | ___| |__ |
* |___| |___._|__|__|_____||_____|__| |___._| |___| |__|_|__|_______|
*
* ============================================================================
* Copyright (c) 2007-2021 Artica Soluciones Tecnologicas, http://www.artica.es
* This code is NOT free software. This code is NOT licenced under GPL2 licence
* You cannnot redistribute it without written permission of copyright holder.
* ============================================================================
*/
require_once $config['homedir'].'/godmode/wizards/Wizard.main.php';
require_once $config['homedir'].'/include/functions_users.php';
require_once $config['homedir'].'/include/class/ExtensionsDiscovery.class.php';
/**
* Implements Wizard to provide generic Custom wizard.
*/
class Custom extends Wizard
{
/**
* Sub-wizard to be launch (vmware,oracle...).
*
* @var string
*/
public $mode;
/**
* Constructor.
*
* @param integer $page Start page, by default 0.
* @param string $msg Default message to show to users.
* @param string $icon Target icon to be used.
* @param string $label Target label to be displayed.
*
* @return mixed
*/
public function __construct(
int $page=0,
string $msg='Default message. Not set.',
string $icon='/images/wizard/Custom_apps@svg.svg',
string $label='Custom'
) {
$this->setBreadcrum([]);
$this->access = 'AW';
$this->task = [];
$this->msg = $msg;
$this->icon = $icon;
$this->class = $class_style;
$this->label = $label;
$this->page = $page;
$this->url = ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=custom'
);
return $this;
}
/**
* Run wizard manager.
*
* @return mixed Returns null if wizard is ongoing. Result if done.
*/
public function run()
{
global $config;
// Load styles.
parent::run();
// Load current wiz. sub-styles.
ui_require_css_file(
'custom',
ENTERPRISE_DIR.'/include/styles/wizards/'
);
$mode = get_parameter('mode', null);
$extensions = new ExtensionsDiscovery('custom', $mode);
if ($mode !== null) {
// Load extension if exist.
$extensions->run();
return;
}
// Load classes and print selector.
$wiz_data = $extensions->loadExtensions();
$this->prepareBreadcrum(
[
[
'link' => ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery'
),
'label' => __('Discovery'),
],
[
'link' => ui_get_full_url(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=custom'
),
'label' => __('Custom'),
'selected' => true,
],
]
);
// Header.
ui_print_page_header(
__('Custom'),
'',
false,
'',
true,
'',
false,
'',
GENERIC_SIZE_TEXT,
'',
$this->printHeader(true)
);
Wizard::printBigButtonsList($wiz_data);
echo '<div class="app_mssg"><i>*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'</i></div>';
return $result;
}
/**
* Check if section have extensions.
*
* @return boolean Return true if section is empty.
*/
public function isEmpty()
{
$extensions = new ExtensionsDiscovery('custom');
$listExtensions = $extensions->getExtensionsApps();
if ($listExtensions > 0) {
return false;
} else {
return true;
}
}
}

View File

@ -168,7 +168,10 @@ class DiscoveryTaskList extends HTML
}
if (is_reporting_console_node() === false) {
$ret2 = $this->showList();
$ret2 = $this->showList(__('Host & devices tasks'), [0, 1]);
$ret2 .= $this->showList(__('Applications tasks'), [3, 4, 5, 10, 11, 12], 'app');
$ret2 .= $this->showList(__('Cloud tasks'), [6, 7, 8, 13, 14], 'cloud');
$ret2 .= $this->showList(__('Custom tasks'), [-1], 'custom');
}
if ($ret === false && $ret2 === false) {
@ -518,9 +521,13 @@ class DiscoveryTaskList extends HTML
/**
* Show complete list of running tasks.
*
* @param string $titleTable Title of section.
* @param array $filter Ids array from apps for filter.
* @param boolean $extension_section Extension to add in table.
*
* @return boolean Success or not.
*/
public function showList()
public function showList($titleTable, $filter, $extension_section=false)
{
global $config;
@ -544,7 +551,16 @@ class DiscoveryTaskList extends HTML
include_once $config['homedir'].'/include/functions_network_profiles.php';
if (users_is_admin()) {
$recon_tasks = db_get_all_rows_sql('SELECT * FROM trecon_task');
$recon_tasks = db_get_all_rows_sql(
sprintf(
'SELECT tasks.*, apps.section AS section, apps.short_name AS short_name
FROM trecon_task tasks
LEFT JOIN tdiscovery_apps apps ON tasks.id_app = apps.id_app
WHERE type IN (%s) OR section = "%s"',
implode(',', $filter),
$extension_section
)
);
} else {
$user_groups = implode(
',',
@ -552,9 +568,14 @@ class DiscoveryTaskList extends HTML
);
$recon_tasks = db_get_all_rows_sql(
sprintf(
'SELECT * FROM trecon_task
WHERE id_group IN (%s)',
$user_groups
'SELECT tasks.*, apps.section AS section, apps.short_name AS short_name
FROM trecon_task
LEFT JOIN tdiscovery_apps apps ON tasks.id_app = apps.id_app
WHERE id_group IN (%s) AND
(type IN (%s) OR section = "%s")',
$user_groups,
implode(',', $filter),
$extension_section
)
);
}
@ -671,7 +692,9 @@ class DiscoveryTaskList extends HTML
$recon_script_name = false;
}
if ($task['disabled'] == 0 && $server_name !== '') {
if (($task['disabled'] == 0 && $server_name !== '' && (int) $task['type'] !== DISCOVERY_EXTENSION)
|| ((int) $task['type'] === DISCOVERY_EXTENSION && (int) $task['setup_complete'] === 1)
) {
if (check_acl($config['id_user'], 0, 'AW')) {
$data[0] = '<span class="link" onclick="force_task(\'';
$data[0] .= ui_get_full_url(
@ -695,7 +718,9 @@ class DiscoveryTaskList extends HTML
);
$data[0] .= '</span>';
}
} else if ($task['disabled'] == 2) {
} else if ($task['disabled'] == 2
|| ((int) $task['type'] === DISCOVERY_EXTENSION && (int) $task['setup_complete'] === 0)
) {
$data[0] = ui_print_help_tip(
__('This task has not been completely defined, please edit it'),
true
@ -856,6 +881,19 @@ class DiscoveryTaskList extends HTML
$data[6] .= __('Discovery.App.Microsoft SQL Server');
break;
case DISCOVERY_EXTENSION:
// Discovery NetScan.
$data[6] = html_print_image(
'images/cluster@os.svg',
true,
[
'title' => $task['short_name'],
'class' => 'main_menu_icon invert_filter',
]
).'&nbsp;&nbsp;';
$data[6] .= $task['short_name'];
break;
case DISCOVERY_HOSTDEVICES:
default:
if ($task['id_recon_script'] == 0) {
@ -954,7 +992,7 @@ class DiscoveryTaskList extends HTML
&& $task['type'] != DISCOVERY_CLOUD_AWS_RDS
&& $task['type'] != DISCOVERY_CLOUD_AWS_S3
) {
if (check_acl($config['id_user'], 0, 'MR')) {
if (check_acl($config['id_user'], 0, 'MR') && (int) $task['type'] !== 15) {
$data[9] .= '<a href="#" onclick="show_map('.$task['id_rt'].',\''.$task['name'].'\')">';
$data[9] .= html_print_image(
'images/web@groups.svg',
@ -1012,13 +1050,24 @@ class DiscoveryTaskList extends HTML
).'</a>';
}
} else {
// Check if is a H&D, Cloud or Application or IPAM.
$data[9] .= '<a href="'.ui_get_full_url(
sprintf(
$url_edit = sprintf(
'index.php?sec=gservers&sec2=godmode/servers/discovery&%s&task=%d',
$this->getTargetWiz($task, $recon_script_data),
$task['id_rt']
)
);
if ((int) $task['type'] === DISCOVERY_EXTENSION) {
$url_edit = sprintf(
'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=%s&mode=%s&id_task=%s',
$task['section'],
$task['short_name'],
$task['id_rt'],
);
}
// Check if is a H&D, Cloud or Application or IPAM.
$data[9] .= '<a href="'.ui_get_full_url(
$url_edit
).'">'.html_print_image(
'images/edit.svg',
true,
@ -1082,7 +1131,7 @@ class DiscoveryTaskList extends HTML
$return = true;
}
ui_toggle($content, __('Server Tasks'), '', '', false);
ui_toggle($content, $titleTable, '', '', false);
// Div neccesary for modal map task.
echo '<div id="map_task" class="invisible"></div>';
@ -1240,7 +1289,7 @@ class DiscoveryTaskList extends HTML
($task['status'] < 0) ? 100 : $task['status'],
150,
150,
'#3A3A3A',
'#14524f',
'%',
'',
'#ececec',
@ -1310,7 +1359,7 @@ class DiscoveryTaskList extends HTML
$task['stats']['c_network_percent'],
150,
150,
'#3A3A3A',
'#14524f',
'%',
'',
'#ececec',
@ -1353,14 +1402,14 @@ class DiscoveryTaskList extends HTML
$output = '';
if (is_array($task['stats']) === false) {
$task['stats'] = json_decode($task['summary'], true);
if (is_array($task['stats']) === false && (int) $task['type'] !== DISCOVERY_EXTENSION) {
$task['stats'] = json_decode(io_safe_output($task['summary']), true);
if (json_last_error() !== JSON_ERROR_NONE) {
return $task['summary'];
}
}
if (is_array($task['stats'])) {
if (is_array($task['stats']) || (int) $task['type'] === DISCOVERY_EXTENSION) {
$i = 0;
$table = new StdClasS();
$table->class = 'databox data';
@ -1418,6 +1467,65 @@ class DiscoveryTaskList extends HTML
$table->data[$i][1] = '<span id="alive">';
$table->data[$i][1] .= ($total - $agents);
$table->data[$i++][1] .= '</span>';
} else if ((int) $task['type'] === DISCOVERY_EXTENSION) {
// Content.
$countSummary = 1;
if (is_array($task['stats']) === true && count(array_filter(array_keys($task['stats']), 'is_numeric')) === count($task['stats'])) {
foreach ($task['stats'] as $key => $summary) {
$table->data[$i][0] = '<b>'.__('Summary').' '.$countSummary.'</b>';
$table->data[$i][1] = '';
$countSummary++;
$i++;
if (is_array($summary) === true) {
if (empty($summary['summary']) === true && empty($summary['info']) === true) {
$table->data[$i][0] = json_encode($summary, JSON_PRETTY_PRINT);
$table->data[$i][1] = '';
$i++;
continue;
}
$unknownJson = $summary;
foreach ($summary as $k2 => $v) {
if (is_array($v) === true) {
if ($k2 === 'summary') {
foreach ($v as $k3 => $v2) {
$table->data[$i][0] = $k3;
$table->data[$i][1] = $v2;
$i++;
}
unset($unknownJson[$k2]);
}
} else {
if ($k2 === 'info') {
$table->data[$i][0] = $v;
$table->data[$i][1] = '';
$i++;
unset($unknownJson[$k2]);
}
}
}
if (empty($unknownJson) === false) {
$table->data[$i][0] = json_encode($unknownJson, JSON_PRETTY_PRINT);
$table->data[$i][1] = '';
$i++;
}
} else {
$table->data[$i][0] = $summary;
$table->data[$i][1] = '';
$i++;
}
}
} else {
$table->data[$i][0] = '<b>'.__('Summary').'</b>';
$table->data[$i][1] = '';
$i++;
$table->data[$i][0] = $task['summary'];
$table->data[$i][1] = '';
$i++;
}
} else {
// Content.
if (is_array($task['stats']['summary']) === true) {
@ -1479,7 +1587,7 @@ class DiscoveryTaskList extends HTML
}
$task = db_get_row('trecon_task', 'id_rt', $id_task);
$task['stats'] = json_decode($task['summary'], true);
$task['stats'] = json_decode(io_safe_output($task['summary']), true);
$summary = $this->progressTaskSummary($task);
$output = '';
@ -1872,7 +1980,11 @@ class DiscoveryTaskList extends HTML
if ($task['status'] <= 0
&& empty($task['summary']) === false
) {
if ($task['status'] == -2) {
$status = __('Failed');
} else {
$status = __('Done');
}
} else if ($task['utimestamp'] == 0
&& empty($task['summary'])
) {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="462px" height="462px" viewBox="0 0 462 462" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
<title>Configurar app@svg</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M170.651341,0 L170.651,0.004 L172.111579,0.00817671226 C263.146802,0.548182735 340,27.8694245 340,92.0575424 L340,247.942458 C340,312.77894 261.586371,340 169.348659,340 L170.651,339.996 L170.651341,340 L170,339.998 L169.348659,340 L169.348659,340 L169.348,339.996 L167.888421,339.991823 C128.247423,339.756679 91.2955334,334.44344 62.2073113,323.219366 L161.855602,223.57095 C187.013424,231.95857 215.800358,226.422038 235.828233,206.394148 C254.435585,187.786783 260.775236,161.559784 254.857225,137.762234 C253.732853,133.229606 248.060798,131.693633 244.757955,134.996478 L207.432822,172.321638 L173.360336,166.644559 L167.683262,132.572049 L205.008395,95.2468889 C208.331316,91.9239659 206.73009,86.2619459 202.167348,85.1275341 C178.384873,79.2346161 152.19805,85.5843105 133.610776,104.166578 C113.713408,124.06396 108.237114,152.90613 116.519318,178.053931 L10.1129522,284.45776 C3.58111026,273.936239 0,261.798287 0,247.942458 L0,92.0575424 C0,27.2210597 78.4136287,0 170.651341,0 L169.348,0.004 L169.348659,0 L170,0.002 L170.651341,0 L170.651341,0 Z" id="path-1"></path>
</defs>
<g id="Configurar-app" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rectangle" transform="translate(61.000000, 61.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Mask" stroke="#555555" stroke-width="14" stroke-linejoin="round" xlink:href="#path-1"></use>
</g>
<g id="Group" transform="translate(107.000000, 136.000000)" stroke="#555555" stroke-width="7">
<circle id="Oval" cx="14.5" cy="14.5" r="14.5"></circle>
<circle id="Oval-Copy" cx="14.5" cy="61.5" r="14.5"></circle>
<circle id="Oval-Copy-2" cx="142.5" cy="208.5" r="14.5"></circle>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="462px" height="462px" viewBox="0 0 462 462" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
<title>Custom apps@svg</title>
<desc>Created with Sketch.</desc>
<g id="Custom-apps" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" transform="translate(61.000000, 61.000000)" stroke="#555555">
<path d="M0,315.724835 L0,274.275165 C0,257.178072 20.6773253,250 45,250 L45,250 C69.3226747,250 90,257.178072 90,274.275165 L90,315.724835 C90,332.821928 69.3226747,340 45,340 L45,340 C20.6773253,340 0,332.821928 0,315.724835 Z" id="Mask" stroke-width="14" stroke-linejoin="round"></path>
<path d="M0,190.724835 L0,149.275165 C0,132.178072 20.6773253,125 45,125 L45,125 C69.3226747,125 90,132.178072 90,149.275165 L90,190.724835 C90,207.821928 69.3226747,215 45,215 L45,215 C20.6773253,215 0,207.821928 0,190.724835 Z" id="Mask-Copy" stroke-width="14" stroke-linejoin="round"></path>
<path d="M0,65.7248353 L0,24.2751647 C0,7.17807242 20.6773253,0 45,0 L45,0 C69.3226747,0 90,7.17807242 90,24.2751647 L90,65.7248353 C90,82.8219276 69.3226747,90 45,90 L45,90 C20.6773253,90 0,82.8219276 0,65.7248353 Z" id="Mask-Copy-2" stroke-width="14" stroke-linejoin="round"></path>
<path d="M125,315.724835 L125,274.275165 C125,257.178072 145.677325,250 170,250 L170,250 C194.322675,250 215,257.178072 215,274.275165 L215,315.724835 C215,332.821928 194.322675,340 170,340 L170,340 C145.677325,340 125,332.821928 125,315.724835 Z" id="Mask" stroke-width="14" stroke-linejoin="round"></path>
<path d="M125,190.724835 L125,149.275165 C125,132.178072 145.677325,125 170,125 L170,125 C194.322675,125 215,132.178072 215,149.275165 L215,190.724835 C215,207.821928 194.322675,215 170,215 L170,215 C145.677325,215 125,207.821928 125,190.724835 Z" id="Mask-Copy" stroke-width="14" stroke-linejoin="round"></path>
<path d="M125,65.7248353 L125,24.2751647 C125,7.17807242 145.677325,0 170,0 L170,0 C194.322675,0 215,7.17807242 215,24.2751647 L215,65.7248353 C215,82.8219276 194.322675,90 170,90 L170,90 C145.677325,90 125,82.8219276 125,65.7248353 Z" id="Mask-Copy-2" stroke-width="14" stroke-linejoin="round"></path>
<path d="M250,190.724835 L250,149.275165 C250,132.178072 270.677325,125 295,125 L295,125 C319.322675,125 340,132.178072 340,149.275165 L340,190.724835 C340,207.821928 319.322675,215 295,215 L295,215 C270.677325,215 250,207.821928 250,190.724835 Z" id="Mask-Copy" stroke-width="14" stroke-linejoin="round"></path>
<path d="M250,65.7248353 L250,24.2751647 C250,7.17807242 270.677325,0 295,0 L295,0 C319.322675,0 340,7.17807242 340,24.2751647 L340,65.7248353 C340,82.8219276 319.322675,90 295,90 L295,90 C270.677325,90 250,82.8219276 250,65.7248353 Z" id="Mask-Copy-2" stroke-width="14" stroke-linejoin="round"></path>
<circle id="Oval" stroke-width="7" cx="45" cy="45" r="15"></circle>
<polygon id="Polygon" stroke-width="7" points="295 155 309.265848 165.364745 303.816779 182.135255 286.183221 182.135255 280.734152 165.364745"></polygon>
<rect id="Rectangle" stroke-width="7" x="155" y="280" width="30" height="30"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="462px" height="462px" viewBox="0 0 462 462" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 61.2 (89653) - https://sketch.com -->
<title>App genérico@svg</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M340,247.942458 C340,312.77894 261.586371,340 169.348659,340 L170.651,339.996 L170.651341,340 L170,339.998 L169.348659,340 L169.348659,340 L169.348,339.996 L167.888421,339.991823 C76.8531975,339.451817 0,312.130576 0,247.942458 L0,92.0575424 C0,27.2210597 78.4136287,0 170.651341,0 L169.348,0.004 L169.348659,0 L170,0.002 L170.651341,0 L170.651341,0 L170.651,0.004 L172.111579,0.00817671226 C263.146802,0.548182735 340,27.8694245 340,92.0575424 Z" id="path-1"></path>
</defs>
<g id="App-genérico" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Rectangle" transform="translate(61.000000, 61.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="Mask" stroke="#555555" stroke-width="14" stroke-linejoin="round" xlink:href="#path-1"></use>
<path d="M243.089632,66.6385397 C255.811455,68.1348967 268.474117,71.8213332 276.910371,78.4128805 C279.780827,80.6195335 283.214489,83.0345401 285.04609,85.6744737 C286.108609,87.2039779 287.599447,90.7246786 286.747539,92.8105813 C285.689754,95.3439706 281.820673,95.5831036 278.614186,95.5168093 C267.669538,95.2682057 257.661988,94.0985848 247.077034,95.3534412 C232.071625,97.1623285 219.643237,101.345972 208.921031,105.81847 C186.274482,115.196745 166.808389,130.69067 151.450385,146.338491 C135.966961,162.071549 121.652544,181.903015 110.248812,202.274305 C97.5530192,224.954058 87.9619574,248.876829 80.0344822,274 C62.0000677,250.340039 50.8566406,221.118459 50,189.124358 L50,189.079372 L50,189.079372 C67.1635754,162.156784 86.968065,137.803101 110.459422,117.133486 C126.655136,102.842329 145.730771,90.113824 166.841519,80.8823431 C170.384035,79.3102211 173.820063,77.3284952 177.646549,76.1044183 C181.43044,74.8637679 185.379979,73.6325881 189.417075,72.3019668 C204.850804,67.2470266 226.07514,64.7278433 243.089632,66.6385397 Z M249.443746,111.548575 C251.871655,112.938928 254.490313,115.160583 256.507696,116.816952 C263.206733,122.210025 268.91885,129.801891 273.814061,136.838864 C280.819956,146.997376 286.722822,158.745753 288.862533,171.957223 C294.066675,204.579596 280.685187,228.427576 263.552985,242.99199 C254.774364,250.4841 243.209143,256.901753 230.756521,260.222805 C216.819372,263.942882 201.165478,264.946679 186.253848,262.930771 C158.17014,259.167051 132.95804,241.350168 116,224.649308 C117.944815,220.058442 118.525357,218.38129 120.519932,213.865241 C123.851827,217.348397 129.769207,221.999533 132.402378,223.828397 C150.61895,236.584729 174.427383,247.587012 205.998488,245.822573 C221.986194,244.978802 236.82733,239.450643 247.36209,231.008769 C257.579625,222.849539 266.134322,211.117788 265.976747,194.763997 C265.812951,177.460443 257.372288,163.326228 248.149968,153.85354 C244.990162,150.594836 241.573259,147.109602 238.121109,144.540878 C232.659869,140.477889 226.584914,137.325176 220.476785,134.344958 C214.262915,131.264983 207.879029,128.18293 200.468828,126.561891 C212.714113,118.797529 245.558263,109.318607 249.443746,111.548575 Z" id="Path-3" stroke="#555555" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" mask="url(#mask-2)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,60 @@
<?php
/**
* Manager extensions ajax
*
* @category Ajax library.
* @package Pandora FMS
* @subpackage Modules.
* @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;
require_once $config['homedir'].'/godmode/wizards/ManageExtensions.class.php';
if (is_ajax() === false) {
exit;
}
// Control call flow.
try {
// User access and validation is being processed on class constructor.
$actions = new ManageExtensions();
} catch (Exception $e) {
exit;
}
// Ajax controller.
$method = get_parameter('method', '');
if (method_exists($actions, $method) === true) {
if ($actions->ajaxMethod($method) === true) {
$actions->{$method}();
} else {
$actions->errorAjax('Unavailable method.');
}
} else {
$actions->errorAjax('Method not found. ['.$method.']');
}
// Stop any execution.
exit;

File diff suppressed because it is too large Load Diff

View File

@ -648,6 +648,7 @@ define('DISCOVERY_APP_DB2', 11);
define('DISCOVERY_APP_MICROSOFT_SQL_SERVER', 12);
define('DISCOVERY_CLOUD_GCP_COMPUTE_ENGINE', 13);
define('DISCOVERY_CLOUD_AWS_S3', 14);
define('DISCOVERY_EXTENSION', 15);
// Force task build tmp results.
define('DISCOVERY_REVIEW', 0);

View File

@ -7975,6 +7975,133 @@ function ui_print_fav_menu($id_element, $url, $label, $section)
}
function ui_print_tree(
$tree,
$id=0,
$depth=0,
$last=0,
$last_array=[],
$sufix=false,
$descriptive_ids=false,
$previous_id=''
) {
static $url = false;
$output = '';
// Get the base URL for images.
if ($url === false) {
$url = ui_get_full_url('operation/tree', false, false, false);
}
// Leaf.
if (empty($tree['__LEAVES__'])) {
return '';
}
$count = 0;
$total = (count(array_keys($tree['__LEAVES__'])) - 1);
$last_array[$depth] = $last;
$class = 'item_'.$depth;
if ($depth > 0) {
$output .= '<ul id="ul_'.$id.'" class="mrgn_0px pdd_0px invisible">';
} else {
$output .= '<ul id="ul_'.$id.'" class="mrgn_0px pdd_0px">';
}
foreach ($tree['__LEAVES__'] as $level => $sub_level) {
// Id used to expand leafs.
$sub_id = time().rand(0, getrandmax());
// Display the branch.
$output .= '<li id="li_'.$sub_id.'" class="'.$class.' mrgn_0px pdd_0px">';
// Indent sub branches.
for ($i = 1; $i <= $depth; $i++) {
if ($last_array[$i] == 1) {
$output .= '<img src="'.$url.'/no_branch.png" class="vertical_middle">';
} else {
$output .= '<img src="'.$url.'/branch.png" class="vertical_middle">';
}
}
// Branch.
if (! empty($sub_level['sublevel']['__LEAVES__'])) {
$output .= "<a id='anchor_$sub_id' onfocus='javascript: this.blur();' href='javascript: toggleTreeNode(\"$sub_id\", \"$id\");'>";
if ($depth == 0 && $count == 0) {
if ($count == $total) {
$output .= '<img src="'.$url.'/one_closed.png" class="vertical_middle">';
} else {
$output .= '<img src="'.$url.'/first_closed.png" class="vertical_middle">';
}
} else if ($count == $total) {
$output .= '<img src="'.$url.'/last_closed.png" class="vertical_middle">';
} else {
$output .= '<img src="'.$url.'/closed.png" class="vertical_middle">';
}
$output .= '</a>';
}
// Leave.
else {
if ($depth == 0 && $count == 0) {
if ($count == $total) {
$output .= '<img src="'.$url.'/no_branch.png" class="vertical_middle">';
} else {
$output .= '<img src="'.$url.'/first_leaf.png" class="vertical_middle">';
}
} else if ($count == $total) {
$output .= '<img src="'.$url.'/last_leaf.png" class="vertical_middle">';
} else {
$output .= '<img src="'.$url.'/leaf.png" class="vertical_middle">';
}
}
$checkbox_name_sufix = ($sufix === true) ? '_'.$level : '';
if ($descriptive_ids === true) {
$checkbox_name = 'create_'.$sub_id.$previous_id.$checkbox_name_sufix;
} else {
$checkbox_name = 'create_'.$sub_id.$checkbox_name_sufix;
}
$previous_id = $checkbox_name_sufix;
if ($sub_level['selectable'] === true) {
$output .= html_print_checkbox(
$sub_level['name'],
$sub_level['value'],
$sub_level['checked'],
true,
false,
'',
true
);
}
$output .= '&nbsp;<span>'.$sub_level['label'].'</span>';
$output .= '</li>';
// Recursively print sub levels.
$output .= ui_print_tree(
$sub_level['sublevel'],
$sub_id,
($depth + 1),
(($count == $total) ? 1 : 0),
$last_array,
$sufix,
$descriptive_ids,
$previous_id
);
$count++;
}
$output .= '</ul>';
return $output;
}
function ui_update_name_fav_element($id_element, $section, $label)
{
$label = io_safe_output($label);

View File

@ -0,0 +1,25 @@
/* global $, interval */
$(document).ready(() => {
if (interval === "0") {
setTimeout(() => {
$("#mode_interval")
.parent()
.find("[id^='interval']")
.hide();
}, 100);
}
});
function changeModeInterval(e) {
if ($(e).val() === "manual") {
$(e)
.parent()
.find("[id^='interval']")
.hide();
} else {
var interval = $(e)
.parent()
.find("div[id^='interval']")[0];
$(interval).show();
}
}

View File

@ -0,0 +1,72 @@
/* globals $, page, url, textsToTranslate, confirmDialog*/
$(document).ready(function() {
function loading(status) {
if (status) {
$(".spinner-fixed").show();
$("#button-upload_button").attr("disabled", "true");
} else {
$(".spinner-fixed").hide();
$("#button-upload_button").removeAttr("disabled");
}
}
$("#uploadExtension").submit(function(e) {
e.preventDefault();
var formData = new FormData(this);
formData.append("page", page);
formData.append("method", "validateIniName");
loading(true);
$.ajax({
method: "POST",
url: url,
data: formData,
processData: false,
contentType: false,
success: function(data) {
loading(false);
data = JSON.parse(data);
if (data.success) {
if (data.warning) {
confirmDialog({
title: textsToTranslate["Warning"],
message: data.message,
strOKButton: textsToTranslate["Confirm"],
strCancelButton: textsToTranslate["Cancel"],
onAccept: function() {
loading(true);
$("#uploadExtension")[0].submit();
},
onDeny: function() {
return false;
}
});
} else {
$("#uploadExtension")[0].submit();
}
} else {
confirmDialog({
title: textsToTranslate["Error"],
message: data.message,
ok: textsToTranslate["Ok"],
hideCancelButton: true,
onAccept: function() {
return false;
}
});
}
},
error: function() {
loading(false);
confirmDialog({
title: textsToTranslate["Error"],
message: textsToTranslate["Failed to upload extension"],
ok: textsToTranslate["Ok"],
hideCancelButton: true,
onAccept: function() {
return false;
}
});
}
});
});
});

View File

@ -4,14 +4,13 @@
ul.bigbuttonlist {
min-height: 200px;
display: flex;
flex-wrap: wrap;
}
li.discovery {
display: inline-block;
float: left;
width: 250px;
margin: 15px;
padding-bottom: 50px;
}
li.discovery > a {
@ -37,8 +36,7 @@ div.data_container {
width: 100%;
height: 100%;
text-align: center;
padding-top: 30px;
padding-bottom: 30px;
padding: 6px;
}
div.data_container:hover {

View File

@ -9018,8 +9018,7 @@ div.graph div.legend table {
}
.app_mssg {
position: absolute;
bottom: 1em;
margin: 1em;
clear: both;
color: #888;
}

View File

@ -237,7 +237,8 @@
.table_action_buttons > img,
.table_action_buttons > button,
.table_action_buttons > form,
.table_action_buttons > div {
.table_action_buttons > div,
.table_action_buttons .action_button_hidden {
visibility: hidden;
}
.info_table > tbody > tr:hover {
@ -250,7 +251,8 @@
.info_table > tbody > tr:hover .table_action_buttons > img,
.info_table > tbody > tr:hover .table_action_buttons > button,
.info_table > tbody > tr:hover .table_action_buttons > form,
.info_table > tbody > tr:hover .table_action_buttons > div {
.info_table > tbody > tr:hover .table_action_buttons > div,
.info_table > tbody > tr:hover .table_action_buttons .action_button_hidden {
visibility: visible;
}

View File

@ -831,6 +831,17 @@ CREATE TABLE IF NOT EXISTS `tmodule_group` (
PRIMARY KEY (`id_mg`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
CREATE TABLE IF NOT EXISTS `tdiscovery_apps` (
`id_app` int(10) auto_increment,
`short_name` varchar(250) NOT NULL DEFAULT '',
`name` varchar(250) NOT NULL DEFAULT '',
`section` varchar(250) NOT NULL DEFAULT 'custom',
`description` varchar(250) NOT NULL DEFAULT '',
`version` varchar(250) NOT NULL DEFAULT '',
PRIMARY KEY (`id_app`),
UNIQUE (`short_name`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- This table was moved cause the `tmodule_relationship` will add
-- a foreign key for the trecon_task(id_rt)
-- ----------------------------------------------------------------------
@ -881,8 +892,12 @@ CREATE TABLE IF NOT EXISTS `trecon_task` (
`type` INT NOT NULL DEFAULT 0,
`subnet_csv` TINYINT UNSIGNED DEFAULT 0,
`snmp_skip_non_enabled_ifs` TINYINT UNSIGNED DEFAULT 1,
`id_app` int(10),
`setup_complete` tinyint unsigned NOT NULL DEFAULT 0,
`executions_timeout` int unsigned NOT NULL DEFAULT 60,
PRIMARY KEY (`id_rt`),
KEY `recon_task_daemon` (`id_recon_server`)
KEY `recon_task_daemon` (`id_recon_server`),
FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- ----------------------------------------------------------------------
@ -4330,6 +4345,44 @@ CREATE TABLE IF NOT EXISTS `tsesion_filter_log_viewer` (
PRIMARY KEY (`id_filter`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- ---------------------------------------------------------------------
-- Table `tdiscovery_apps_scripts`
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_scripts` (
`id_app` int(10),
`macro` varchar(250) NOT NULL DEFAULT '',
`value` text NOT NULL DEFAULT '',
PRIMARY KEY (`id_app`, `macro`),
FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- ---------------------------------------------------------------------
-- Table `tdiscovery_apps_executions`
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_executions` (
`id` int(10) unsigned NOT NULL auto_increment,
`id_app` int(10),
`execution` text NOT NULL DEFAULT '',
PRIMARY KEY (`id`, `id_app`),
FOREIGN KEY (`id_app`) REFERENCES tdiscovery_apps(`id_app`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- ---------------------------------------------------------------------
-- Table `tdiscovery_apps_tasks_macros`
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `tdiscovery_apps_tasks_macros` (
`id_task` int(10) unsigned NOT NULL,
`macro` varchar(250) NOT NULL DEFAULT '',
`type` varchar(250) NOT NULL DEFAULT 'custom',
`value` text NOT NULL DEFAULT '',
`temp_conf` tinyint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id_task`, `macro`),
FOREIGN KEY (`id_task`) REFERENCES trecon_task(`id_rt`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
-- ---------------------------------------------------------------------
-- Table `tnetwork_explorer_filter`
-- ---------------------------------------------------------------------

View File

@ -62,6 +62,7 @@ our @EXPORT = qw(
set_update_agent
set_update_agentmodule
get_action_id
get_action_name
get_addr_id
get_agent_addr_id
get_agent_id
@ -102,6 +103,8 @@ our @EXPORT = qw(
get_server_id
get_tag_id
get_tag_name
get_template_id
get_template_name
get_group_name
get_template_id
get_template_module_id
@ -257,15 +260,28 @@ sub get_console_api_url ($$) {
}
########################################################################
## Return action ID given the action name.
## Return the ID of an alert action given its name.
########################################################################
sub get_action_id ($$) {
my ($dbh, $action_name) = @_;
my $rc = get_db_value ($dbh, "SELECT id FROM talert_actions WHERE name = ?", $action_name);
my $rc = get_db_value ($dbh, "SELECT id FROM talert_actions
WHERE name = ?", safe_input($action_name));
return defined ($rc) ? $rc : -1;
}
########################################################################
## Return the name of an alert action given its ID.
########################################################################
sub get_action_name ($$) {
my ($dbh, $action_id) = @_;
my $rc = get_db_value ($dbh, "SELECT name FROM talert_actions
WHERE id = ?", safe_input($action_id));
return defined ($rc) ? $rc : -1;
}
########################################################################
## Return command ID given the command name.
########################################################################
@ -304,6 +320,29 @@ sub get_agent_ids_from_alias ($$) {
return @rc;
}
########################################################################
## Return the ID of an alert template given its name.
########################################################################
sub get_template_id ($$) {
my ($dbh, $template_name) = @_;
my $rc = get_db_value ($dbh, "SELECT id FROM talert_templates
WHERE name = ?", safe_input($template_name));
return defined ($rc) ? $rc : -1;
}
########################################################################
## Return the name of an alert template given its ID.
########################################################################
sub get_template_name ($$) {
my ($dbh, $template_id) = @_;
my $rc = get_db_value ($dbh, "SELECT name FROM talert_templates
WHERE id = ?", safe_input($template_id));
return defined ($rc) ? $rc : -1;
}
########################################################################
## Return server ID given the name of server.
########################################################################
@ -698,24 +737,6 @@ sub get_agent_module_id ($$$) {
return defined ($rc) ? $rc : -1;
}
##########################################################################
## Return template id given the template name.
##########################################################################
sub get_template_id ($$) {
my ($dbh, $template_name) = @_;
my $field;
if ($RDBMS eq 'oracle') {
$field = "to_char(name)";
}
else {
$field = "name";
}
my $rc = get_db_value ($dbh, "SELECT id FROM talert_templates WHERE $field = ?", safe_input($template_name));
return defined ($rc) ? $rc : -1;
}
##########################################################################
## Return the module template id given the module id and the template id.
##########################################################################

View File

@ -68,6 +68,7 @@ use constant {
DISCOVERY_REVIEW => 0,
DISCOVERY_STANDARD => 1,
DISCOVERY_RESULTS => 2,
DISCOVERY_APP => 15,
};
################################################################################
@ -147,17 +148,23 @@ sub data_producer ($) {
WHERE id_recon_server = ?
AND disabled = 0
AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
OR (status < 0 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id);
} else {
@rows = get_db_rows ($dbh, 'SELECT * FROM trecon_task
WHERE (id_recon_server = ? OR id_recon_server NOT IN (SELECT id_server FROM tserver WHERE status = 1 AND server_type = ?))
AND disabled = 0
AND ((utimestamp = 0 AND interval_sweep != 0 OR status = 1)
OR (status = -1 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER);
OR (status < 0 AND interval_sweep > 0 AND (utimestamp + interval_sweep) < UNIX_TIMESTAMP()))', $server_id, DISCOVERYSERVER);
}
foreach my $row (@rows) {
# Discovery apps must be fully set up.
if ($row->{'type'} == DISCOVERY_APP && $row->{'setup_complete'} != 1) {
logger($pa_config, 'Setup for recon app task ' . $row->{'id_app'} . ' not complete.', 10);
next;
}
# Update task status
update_recon_task ($dbh, $row->{'id_rt'}, 1);
@ -185,7 +192,13 @@ sub data_consumer ($$) {
if (defined ($task->{'id_recon_script'}) && ($task->{'id_recon_script'} != 0)) {
exec_recon_script ($pa_config, $dbh, $task);
return;
} else {
}
# Is it a discovery app?
elsif ($task->{'type'} == DISCOVERY_APP) {
exec_recon_app ($pa_config, $dbh, $task);
return;
}
else {
logger($pa_config, 'Starting recon task for net ' . $task->{'subnet'} . '.', 10);
}
@ -407,7 +420,373 @@ sub exec_recon_script ($$$) {
}
################################################################################
# Guess the OS using nmap.
# Executes recon apps.
################################################################################
sub exec_recon_app ($$$) {
my ($pa_config, $dbh, $task) = @_;
# Get execution, macro and script data.
my @executions = get_db_rows($dbh, 'SELECT * FROM tdiscovery_apps_executions WHERE id_app = ?', $task->{'id_app'});
my @scripts = get_db_rows($dbh, 'SELECT * FROM tdiscovery_apps_scripts WHERE id_app = ?', $task->{'id_app'});
logger($pa_config, 'Executing recon app ID ' . $task->{'id_app'}, 10);
# Configure macros.
my %macros = (
"__taskMD5__" => md5($task->{'id_rt'}),
"__taskInterval__" => $task->{'interval_sweep'},
"__taskGroup__" => get_group_name($dbh, $task->{'id_group'}),
"__taskGroupID__" => $task->{'id_group'},
"__temp__" => $pa_config->{'temporal'},
"__incomingDir__" => $pa_config->{'incomingdir'},
"__consoleAPIURL__" => $pa_config->{'console_api_url'},
"__consoleAPIPass__" => $pa_config->{'console_api_pass'},
"__consoleUser__" => $pa_config->{'console_user'},
"__consolePass__" => $pa_config->{'console_pass'},
get_recon_app_macros($pa_config, $dbh, $task),
get_recon_script_macros($pa_config, $dbh, $task)
);
# Dump macros to disk.
dump_recon_app_macros($pa_config, $dbh, $task, \%macros);
# Run executions.
my $status = -1;
my @summary;
for (my $i = 0; $i < scalar(@executions); $i++) {
my $execution = $executions[$i];
# NOTE: Add the redirection before calling subst_alert_macros to prevent it from escaping quotes.
my $cmd = $pa_config->{'plugin_exec'} . ' ' . $task->{'executions_timeout'} . ' ' .
subst_alert_macros(safe_output($execution->{'execution'}) . ' 2>&1', \%macros);
logger($pa_config, 'Executing command for recon app ID ' . $task->{'id_app'} . ': ' . $cmd, 10);
my $output_json = `$cmd`;
# Something went wrong.
my $rc = $? >> 8;
if ($rc != 0) {
$status = -2;
}
# Timeout specific mesage.
if ($rc == 124) {
push(@summary, "The execution timed out.");
next;
}
# No output message.
if (!defined($output_json)) {
push(@summary, "The execution returned no output.");
next;
}
# Parse the output.
my $output = eval {
local $SIG{'__DIE__'};
decode_json($output_json);
};
# Non-JSON output.
if (!defined($output)) {
push(@summary, $output_json);
next;
}
# Process monitoring data.
if (defined($output->{'monitoring_data'})) {
my $recon = new PandoraFMS::Recon::Base(
dbh => $dbh,
group_id => $task->{'id_group'},
id_os => $task->{'id_os'},
pa_config => $pa_config,
snmp_enabled => 0,
task_id => $task->{'id_rt'},
task_data => $task,
);
$recon->create_agents($output->{'monitoring_data'});
delete($output->{'monitoring_data'});
}
# Store output data.
push(@summary, $output);
# Update the progress.
update_recon_task($dbh, $task->{'id_rt'}, int((100 * ($i + 1)) / scalar(@executions)));
}
# Parse the output.
my $summary_json = eval {
local $SIG{'__DIE__'};
encode_json(\@summary);
};
if (!defined($summary_json)) {
logger($pa_config, 'Invalid summary for recon app ID ' . $task->{'id_app'}, 10);
} else {
db_do($dbh, "UPDATE trecon_task SET summary=? WHERE id_rt=?", $summary_json, $task->{'id_rt'});
}
update_recon_task($dbh, $task->{'id_rt'}, $status);
return;
}
################################################################################
# Processe app macros and return them ready to be used by subst_alert_macros.
################################################################################
sub get_recon_app_macros ($$$) {
my ($pa_config, $dbh, $task) = @_;
my %macros;
# Get a list of macros for the given task.
my @macro_array = get_db_rows($dbh, 'SELECT * FROM tdiscovery_apps_tasks_macros WHERE id_task = ?', $task->{'id_rt'});
foreach my $macro_item (@macro_array) {
my $macro_id = safe_output($macro_item->{'id_task'});
my $macro_name = safe_output($macro_item->{'macro'});
my $macro_type = $macro_item->{'type'};
my $macro_value = safe_output($macro_item->{'value'});
my $computed_value = '';
# The value can be a JSON array of values.
my $value_array = eval {
local $SIG{'__DIE__'};
decode_json($macro_value);
};
if (defined($value_array) && ref($value_array) eq 'ARRAY') {
# Multi value macro.
my @tmp;
foreach my $value_item (@{$value_array}) {
push(@tmp, get_recon_macro_value($pa_config, $dbh, $macro_type, $value_item));
}
$computed_value = p_encode_json($pa_config, \@tmp);
if (!defined($computed_value)) {
logger($pa_config, "Error encoding macro $macro_name for task ID " . $task->{'id_rt'}, 10);
next;
}
} else {
# Single value macro.
$computed_value = get_recon_macro_value($pa_config, $dbh, $macro_type, $macro_value);
}
# Store the computed value.
$macros{$macro_name} = $computed_value;
}
return %macros;
}
################################################################################
# Dump macros that must be saved to disk.
# The macros dictionary is modified in-place.
################################################################################
sub dump_recon_app_macros ($$$$) {
my ($pa_config, $dbh, $task, $macros) = @_;
# Get a list of macros that must be dumped to disk.
my @macro_array = get_db_rows($dbh, 'SELECT * FROM tdiscovery_apps_tasks_macros WHERE id_task = ? AND temp_conf = 1', $task->{'id_rt'});
foreach my $macro_item (@macro_array) {
# Make sure the macro has already been parsed.
my $macro_name = safe_output($macro_item->{'macro'});
next unless defined($macros->{$macro_name});
my $macro_value = $macros->{$macro_name};
my $macro_id = safe_output($macro_item->{'id_task'});
# Save the computed value to a temporary file.
my $temp_dir = $pa_config->{'incomingdir'} . '/discovery/tmp';
mkdir($temp_dir) if (! -d $temp_dir);
my $fname = $temp_dir . '/' . md5($task->{'id_rt'} . '_' . $macro_name) . '.macro';
eval {
open(my $fh, '>', $fname) or die($!);
print $fh subst_alert_macros($macro_value, $macros);
close($fh);
};
if ($@) {
logger($pa_config, "Error writing macro $macro_name for task ID " . $task->{'id_rt'} . " to disk: $@", 10);
next;
}
# Set the macro value to the temporary file name.
$macros->{$macro_name} = $fname;
}
}
################################################################################
# Processe recon script macros and return them ready to be used by
# subst_alert_macros.
################################################################################
sub get_recon_script_macros ($$$) {
my ($pa_config, $dbh, $task) = @_;
my %macros;
# Get a list of script macros.
my @macro_array = get_db_rows($dbh, 'SELECT * FROM tdiscovery_apps_scripts WHERE id_app = ?', $task->{'id_app'});
foreach my $macro_item (@macro_array) {
my $macro_name = safe_output($macro_item->{'macro'});
my $macro_value = safe_output($macro_item->{'value'});
# Compose the full path to the script: <incoming dir>/discovery/<app short name>/<script>
my $app = get_db_single_row($dbh, 'SELECT short_name FROM tdiscovery_apps WHERE id_app = ?', $task->{'id_app'});
if (!defined($app)) {
logger($pa_config, "Discovery app with ID " . $task->{'id_app'} . " not found.", 10);
next;
}
my $app_short_name = safe_output($app->{'short_name'});
$macros{$macro_name} = $pa_config->{'incomingdir'} . '/discovery/' . $app_short_name . '/' . $macro_value;
}
return %macros;
}
################################################################################
# Return the replacement value for the given macro.
################################################################################
sub get_recon_macro_value($$$$) {
my ($pa_config, $dbh, $type, $value) = @_;
my $ret = '';
# These macros return the macro value itself.
if ($type eq 'custom' ||
$type eq 'interval' ||
$type eq 'module_types' ||
$type eq 'status') {
$ret = $value;
}
# Name of the group if it exists. Empty otherwise.
elsif ($type eq 'agent_groups') {
my $group_name = get_group_name($dbh, $value);
if (defined($group_name)) {
$ret = $group_name;
}
}
# Name of the agent if it exists. Empty otherwise.
elsif ($type eq 'agents') {
my $agent_id = get_agent_id($dbh, $value);
if ($agent_id > 0) {
$ret = $value;
}
}
# Name of the module group if it exists. Empty otherwise.
elsif ($type eq 'module_groups') {
my $module_group_name = get_module_group_name($dbh, $value);
if (defined($module_group_name)) {
$ret = $module_group_name;
}
}
# Name of the module if it exists. Empty otherwise.
elsif ($type eq 'modules') {
my $module_id = get_db_value ($dbh, "SELECT id_agente_modulo FROM tagente_modulo WHERE nombre = ?", safe_input($value));
if ($module_id > 0) {
$ret = $value;
}
}
# Name of the tag if it exists. Empty otherwise.
elsif ($type eq 'tags') {
my $tag_name = get_tag_name($dbh, $value);
if (defined($tag_name)) {
$ret = $tag_name;
}
}
# Name of the alert template if it exists. Empty otherwise.
elsif ($type eq 'alert_templates') {
my $template_name = get_template_name($dbh, $value);
if (defined($template_name)) {
$ret = $template_name;
}
}
# Name of the alert action if it exists. Empty otherwise.
elsif ($type eq 'alert_actions') {
my $action_name = get_action_name($dbh, $value);
if (defined($action_name)) {
$ret = $action_name;
}
}
# Name of the OS if it exists. Empty otherwise.
elsif ($type eq 'os') {
my $os_name = get_os_name($dbh, $value);
if (defined($os_name)) {
$ret = $os_name;
}
}
# Credentials from the Pandora DB.
elsif ($type =~ m/^credentials\./) {
$ret = get_recon_credential_macro($pa_config, $dbh, $value);
}
return $ret;
}
################################################################################
# Return the value for a credential macro.
################################################################################
sub get_recon_credential_macro($$$) {
my ($pa_config, $dbh, $credential_id) = @_;
my $cred_dict = {};
my $cred_json = undef;
# Retrieve the credentials.
my $cred = get_db_single_row($dbh, 'SELECT * FROM tcredential_store WHERE identifier = ?', $credential_id);
return '' unless defined($cred);
# Generate the appropriate output for each product.
my $product = uc($cred->{'product'});
if ($product eq 'CUSTOM') {
$cred_dict = {
'user' => safe_output($cred->{'username'}),
'password' => safe_output($cred->{'password'})
};
}
elsif ($product eq 'AWS') {
$cred_dict = {
'access_key_id' => safe_output($cred->{'username'}),
'secret_access_key' => safe_output($cred->{'password'})
};
}
elsif ($product eq 'AZURE') {
$cred_dict = {
'client_id' => safe_output($cred->{'username'}),
'application_secret' => safe_output($cred->{'password'}),
'tenant_domain' => safe_output($cred->{'extra_1'}),
'subscription_id' => safe_output($cred->{'extra_2'})
};
}
elsif ($product eq 'GOOGLE') {
$cred_json = safe_output($cred->{'extra_1'});
}
elsif ($product eq 'SAP') {
$cred_dict = {
'user' => safe_output($cred->{'username'}),
'password' => safe_output($cred->{'password'})
};
}
elsif ($product eq 'SNMP') {
$cred_json = safe_output($cred->{'extra_1'});
}
elsif ($product eq 'WMI') {
$cred_dict = {
'user' => safe_output($cred->{'username'}),
'password' => safe_output($cred->{'password'}),
'namespace' => safe_output($cred->{'extra_1'})
};
}
# Encode to JSON if needed.
if (!defined($cred_json)) {
$cred_json = p_encode_json($pa_config, $cred_dict);
if (!defined($cred_json)) {
logger($pa_config, "Error encoding credential $credential_id to JSON.", 10);
return '';
}
}
# Return the base 64 encoding of the credential JSON.
return encode_base64($cred_json, '');
}
################################################################################
# Guess the OS using xprobe2 or nmap.
################################################################################
sub PandoraFMS::Recon::Base::guess_os($$;$) {
my ($self, $device, $string_flag) = @_;