diff --git a/extras/deploy-scripts/deploy_ext_database_el8.sh b/extras/deploy-scripts/deploy_ext_database_el8.sh index 3ff86cc56b..4417265599 100644 --- a/extras/deploy-scripts/deploy_ext_database_el8.sh +++ b/extras/deploy-scripts/deploy_ext_database_el8.sh @@ -19,10 +19,10 @@ LOGFILE="/tmp/deploy-ext-db-$(date +%F).log" [ "$DBHOST" ] || DBHOST=127.0.0.1 [ "$DBNAME" ] || DBNAME=pandora [ "$DBUSER" ] || DBUSER=pandora -[ "$DBPASS" ] || DBPASS=pandora +[ "$DBPASS" ] || DBPASS='Pandor4!' [ "$DBPORT" ] || DBPORT=3306 [ "$DBROOTUSER" ] || DBROOTUSER=root -[ "$DBROOTPASS" ] || DBROOTPASS=pandora +[ "$DBROOTPASS" ] || DBROOTPASS='Pandor4!' [ "$SKIP_DATABASE_INSTALL" ] || SKIP_DATABASE_INSTALL=0 [ "$SKIP_KERNEL_OPTIMIZATIONS" ] || SKIP_KERNEL_OPTIMIZATIONS=0 [ "$POOL_SIZE" ] || POOL_SIZE=$(grep -i total /proc/meminfo | head -1 | awk '{printf "%.2f \n", $(NF-1)*0.4/1024}' | sed "s/\\..*$/M/g") @@ -79,6 +79,53 @@ check_root_permissions () { fi } +# Function to check if a password meets the MySQL secure password requirements +is_mysql_secure_password() { + local password=$1 + + # Check password length (at least 8 characters) + if [[ ${#password} -lt 8 ]]; then + echo "Password length should be at least 8 characters." + return 1 + fi + + # Check if password contains at least one uppercase letter + if [[ $password == ${password,,} ]]; then + echo "Password should contain at least one uppercase letter." + return 1 + fi + + # Check if password contains at least one lowercase letter + if [[ $password == ${password^^} ]]; then + echo "Password should contain at least one lowercase letter." + return 1 + fi + + # Check if password contains at least one digit + if ! [[ $password =~ [0-9] ]]; then + echo "Password should contain at least one digit." + return 1 + fi + + # Check if password contains at least one special character + if ! [[ $password =~ [[:punct:]] ]]; then + echo "Password should contain at least one special character." + return 1 + fi + + # Check if password is not a common pattern (e.g., "password", "123456") + local common_patterns=("password" "123456" "qwerty") + for pattern in "${common_patterns[@]}"; do + if [[ $password == *"$pattern"* ]]; then + echo "Password should not contain common patterns." + return 1 + fi + done + + # If all checks pass, the password is MySQL secure compliant + return 0 +} + ## Main echo "Starting PandoraFMS External DB deployment EL8 ver. $S_VERSION" @@ -128,6 +175,10 @@ execute_cmd "grep --version" 'Checking needed tools: grep' execute_cmd "sed --version" 'Checking needed tools: sed' execute_cmd "dnf --version" 'Checking needed tools: dnf' +#Check mysql pass +execute_cmd "is_mysql_secure_password $DBROOTPASS" "Checking DBROOTPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' +execute_cmd "is_mysql_secure_password $DBPASS" "Checking DBPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' + # Creating working directory rm -rf "$HOME"/pandora_deploy_tmp/*.rpm* &>> "$LOGFILE" mkdir "$HOME"/pandora_deploy_tmp &>> "$LOGFILE" @@ -207,16 +258,12 @@ if [ "$SKIP_DATABASE_INSTALL" -eq '0' ] ; then export MYSQL_PWD=$(grep "temporary password" /var/log/mysqld.log | rev | cut -d' ' -f1 | rev) if [ "$MYVER" -eq '80' ] ; then echo """ - SET PASSWORD FOR '$DBROOTUSER'@'localhost' = 'Pandor4!'; - UNINSTALL COMPONENT 'file://component_validate_password'; SET PASSWORD FOR '$DBROOTUSER'@'localhost' = '$DBROOTPASS'; """ | mysql --connect-expired-password -u$DBROOTUSER &>> "$LOGFILE" fi if [ "$MYVER" -ne '80' ] ; then echo """ - SET PASSWORD FOR '$DBROOTUSER'@'localhost' = PASSWORD('Pandor4!'); - UNINSTALL PLUGIN validate_password; SET PASSWORD FOR '$DBROOTUSER'@'localhost' = PASSWORD('$DBROOTPASS'); """ | mysql --connect-expired-password -u$DBROOTUSER &>> "$LOGFILE"fi fi diff --git a/extras/deploy-scripts/deploy_ext_database_ubuntu_2204.sh b/extras/deploy-scripts/deploy_ext_database_ubuntu_2204.sh index 21f9b21fa0..767be5632f 100644 --- a/extras/deploy-scripts/deploy_ext_database_ubuntu_2204.sh +++ b/extras/deploy-scripts/deploy_ext_database_ubuntu_2204.sh @@ -26,9 +26,9 @@ rm -f $LOGFILE &> /dev/null # remove last log before start [ "$DBHOST" ] || DBHOST=127.0.0.1 [ "$DBNAME" ] || DBNAME=pandora [ "$DBUSER" ] || DBUSER=pandora -[ "$DBPASS" ] || DBPASS=pandora +[ "$DBPASS" ] || DBPASS='Pandor4!' [ "$DBPORT" ] || DBPORT=3306 -[ "$DBROOTPASS" ] || DBROOTPASS=pandora +[ "$DBROOTPASS" ] || DBROOTPASS='Pandor4!' [ "$SKIP_DATABASE_INSTALL" ] || SKIP_DATABASE_INSTALL=0 [ "$SKIP_KERNEL_OPTIMIZATIONS" ] || SKIP_KERNEL_OPTIMIZATIONS=0 [ "$POOL_SIZE" ] || POOL_SIZE=$(grep -i total /proc/meminfo | head -1 | awk '{printf "%.2f \n", $(NF-1)*0.4/1024}' | sed "s/\\..*$/M/g") @@ -86,6 +86,53 @@ check_root_permissions () { fi } +# Function to check if a password meets the MySQL secure password requirements +is_mysql_secure_password() { + local password=$1 + + # Check password length (at least 8 characters) + if [[ ${#password} -lt 8 ]]; then + echo "Password length should be at least 8 characters." + return 1 + fi + + # Check if password contains at least one uppercase letter + if [[ $password == ${password,,} ]]; then + echo "Password should contain at least one uppercase letter." + return 1 + fi + + # Check if password contains at least one lowercase letter + if [[ $password == ${password^^} ]]; then + echo "Password should contain at least one lowercase letter." + return 1 + fi + + # Check if password contains at least one digit + if ! [[ $password =~ [0-9] ]]; then + echo "Password should contain at least one digit." + return 1 + fi + + # Check if password contains at least one special character + if ! [[ $password =~ [[:punct:]] ]]; then + echo "Password should contain at least one special character." + return 1 + fi + + # Check if password is not a common pattern (e.g., "password", "123456") + local common_patterns=("password" "123456" "qwerty") + for pattern in "${common_patterns[@]}"; do + if [[ $password == *"$pattern"* ]]; then + echo "Password should not contain common patterns." + return 1 + fi + done + + # If all checks pass, the password is MySQL secure compliant + return 0 +} + ## Main echo "Starting PandoraFMS External DB deployment Ubuntu 22.04 ver. $S_VERSION" @@ -137,6 +184,10 @@ execute_cmd "grep --version" 'Checking needed tools: grep' execute_cmd "sed --version" 'Checking needed tools: sed' execute_cmd "apt --version" 'Checking needed tools: apt' +#Check mysql pass +execute_cmd "is_mysql_secure_password $DBROOTPASS" "Checking DBROOTPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' +execute_cmd "is_mysql_secure_password $DBPASS" "Checking DBPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' + # Creating working directory rm -rf "$WORKDIR" &>> "$LOGFILE" mkdir -p "$WORKDIR" &>> "$LOGFILE" @@ -170,6 +221,7 @@ if [ "$SKIP_DATABASE_INSTALL" -eq '0' ] ; then """ | mysql -uroot &>> "$LOGFILE" export MYSQL_PWD=$DBROOTPASS + echo "INSTALL COMPONENT 'file://component_validate_password';" | mysql -uroot -P$DBPORT -h$DBHOST &>> "$LOGFILE" echo -en "${cyan}Creating Pandora FMS database...${reset}" echo "create database $DBNAME" | mysql -uroot -P$DBPORT -h$DBHOST check_cmd_status "Error creating database $DBNAME, is this an empty node? if you have a previus installation please contact with support." diff --git a/extras/deploy-scripts/pandora_deploy_community_el8.sh b/extras/deploy-scripts/pandora_deploy_community_el8.sh index 3b4dde6cef..32422ab98b 100644 --- a/extras/deploy-scripts/pandora_deploy_community_el8.sh +++ b/extras/deploy-scripts/pandora_deploy_community_el8.sh @@ -24,10 +24,10 @@ LOGFILE="/tmp/pandora-deploy-community-$(date +%F).log" [ "$DBHOST" ] || DBHOST=127.0.0.1 [ "$DBNAME" ] || DBNAME=pandora [ "$DBUSER" ] || DBUSER=pandora -[ "$DBPASS" ] || DBPASS=pandora +[ "$DBPASS" ] || DBPASS='Pandor4!' [ "$DBPORT" ] || DBPORT=3306 [ "$DBROOTUSER" ] || DBROOTUSER=root -[ "$DBROOTPASS" ] || DBROOTPASS=pandora +[ "$DBROOTPASS" ] || DBROOTPASS='Pandor4!' [ "$SKIP_PRECHECK" ] || SKIP_PRECHECK=0 [ "$SKIP_DATABASE_INSTALL" ] || SKIP_DATABASE_INSTALL=0 [ "$SKIP_KERNEL_OPTIMIZATIONS" ] || SKIP_KERNEL_OPTIMIZATIONS=0 @@ -125,6 +125,52 @@ installing_docker () { echo "End installig docker" &>> "$LOGFILE" } +# Function to check if a password meets the MySQL secure password requirements +is_mysql_secure_password() { + local password=$1 + + # Check password length (at least 8 characters) + if [[ ${#password} -lt 8 ]]; then + echo "Password length should be at least 8 characters." + return 1 + fi + + # Check if password contains at least one uppercase letter + if [[ $password == ${password,,} ]]; then + echo "Password should contain at least one uppercase letter." + return 1 + fi + + # Check if password contains at least one lowercase letter + if [[ $password == ${password^^} ]]; then + echo "Password should contain at least one lowercase letter." + return 1 + fi + + # Check if password contains at least one digit + if ! [[ $password =~ [0-9] ]]; then + echo "Password should contain at least one digit." + return 1 + fi + + # Check if password contains at least one special character + if ! [[ $password =~ [[:punct:]] ]]; then + echo "Password should contain at least one special character." + return 1 + fi + + # Check if password is not a common pattern (e.g., "password", "123456") + local common_patterns=("password" "123456" "qwerty") + for pattern in "${common_patterns[@]}"; do + if [[ $password == *"$pattern"* ]]; then + echo "Password should not contain common patterns." + return 1 + fi + done + + # If all checks pass, the password is MySQL secure compliant + return 0 +} ## Main echo "Starting PandoraFMS Community deployment EL8 ver. $S_VERSION" @@ -189,6 +235,10 @@ execute_cmd "grep --version" 'Checking needed tools: grep' execute_cmd "sed --version" 'Checking needed tools: sed' execute_cmd "dnf --version" 'Checking needed tools: dnf' +#Check mysql pass +execute_cmd "is_mysql_secure_password $DBROOTPASS" "Checking DBROOTPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' +execute_cmd "is_mysql_secure_password $DBPASS" "Checking DBPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' + # Creating working directory rm -rf "$HOME"/pandora_deploy_tmp/*.rpm* &>> "$LOGFILE" mkdir "$HOME"/pandora_deploy_tmp &>> "$LOGFILE" @@ -437,7 +487,6 @@ if [ "$SKIP_DATABASE_INSTALL" -eq '0' ] ; then if [ "$MYVER" -eq '80' ] ; then echo """ SET PASSWORD FOR '$DBROOTUSER'@'localhost' = 'Pandor4!'; - UNINSTALL COMPONENT 'file://component_validate_password'; SET PASSWORD FOR '$DBROOTUSER'@'localhost' = '$DBROOTPASS'; """ | mysql --connect-expired-password -u$DBROOTUSER &>> "$LOGFILE" fi @@ -445,7 +494,6 @@ if [ "$SKIP_DATABASE_INSTALL" -eq '0' ] ; then if [ "$MYVER" -ne '80' ] ; then echo """ SET PASSWORD FOR '$DBROOTUSER'@'localhost' = PASSWORD('Pandor4!'); - UNINSTALL PLUGIN validate_password; SET PASSWORD FOR '$DBROOTUSER'@'localhost' = PASSWORD('$DBROOTPASS'); """ | mysql --connect-expired-password -u$DBROOTUSER &>> "$LOGFILE"fi fi diff --git a/extras/deploy-scripts/pandora_deploy_community_ubuntu_2204.sh b/extras/deploy-scripts/pandora_deploy_community_ubuntu_2204.sh index 7e2ff6f532..a215808d17 100644 --- a/extras/deploy-scripts/pandora_deploy_community_ubuntu_2204.sh +++ b/extras/deploy-scripts/pandora_deploy_community_ubuntu_2204.sh @@ -27,9 +27,9 @@ rm -f $LOGFILE &> /dev/null # remove last log before start [ "$DBHOST" ] || DBHOST=127.0.0.1 [ "$DBNAME" ] || DBNAME=pandora [ "$DBUSER" ] || DBUSER=pandora -[ "$DBPASS" ] || DBPASS=pandora +[ "$DBPASS" ] || DBPASS='Pandor4!' [ "$DBPORT" ] || DBPORT=3306 -[ "$DBROOTPASS" ] || DBROOTPASS=pandora +[ "$DBROOTPASS" ] || DBROOTPASS='Pandor4!' [ "$SKIP_PRECHECK" ] || SKIP_PRECHECK=0 [ "$SKIP_DATABASE_INSTALL" ] || SKIP_DATABASE_INSTALL=0 [ "$SKIP_KERNEL_OPTIMIZATIONS" ] || SKIP_KERNEL_OPTIMIZATIONS=0 @@ -113,6 +113,53 @@ check_root_permissions () { fi } +# Function to check if a password meets the MySQL secure password requirements +is_mysql_secure_password() { + local password=$1 + + # Check password length (at least 8 characters) + if [[ ${#password} -lt 8 ]]; then + echo "Password length should be at least 8 characters." + return 1 + fi + + # Check if password contains at least one uppercase letter + if [[ $password == ${password,,} ]]; then + echo "Password should contain at least one uppercase letter." + return 1 + fi + + # Check if password contains at least one lowercase letter + if [[ $password == ${password^^} ]]; then + echo "Password should contain at least one lowercase letter." + return 1 + fi + + # Check if password contains at least one digit + if ! [[ $password =~ [0-9] ]]; then + echo "Password should contain at least one digit." + return 1 + fi + + # Check if password contains at least one special character + if ! [[ $password =~ [[:punct:]] ]]; then + echo "Password should contain at least one special character." + return 1 + fi + + # Check if password is not a common pattern (e.g., "password", "123456") + local common_patterns=("password" "123456" "qwerty") + for pattern in "${common_patterns[@]}"; do + if [[ $password == *"$pattern"* ]]; then + echo "Password should not contain common patterns." + return 1 + fi + done + + # If all checks pass, the password is MySQL secure compliant + return 0 +} + installing_docker () { #Installing docker for debug echo "Start installig docker" &>> "$LOGFILE" @@ -194,6 +241,10 @@ execute_cmd "grep --version" 'Checking needed tools: grep' execute_cmd "sed --version" 'Checking needed tools: sed' execute_cmd "apt --version" 'Checking needed tools: apt' +#Check mysql pass +execute_cmd "is_mysql_secure_password $DBROOTPASS" "Checking DBROOTPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' +execute_cmd "is_mysql_secure_password $DBPASS" "Checking DBPASS password match policy" 'This password do not match minimum MySQL policy requirements, more info in: https://dev.mysql.com/doc/refman/8.0/en/validate-password.html' + # Creating working directory rm -rf "$WORKDIR" &>> "$LOGFILE" mkdir -p "$WORKDIR" &>> "$LOGFILE" @@ -286,6 +337,7 @@ server_dependencies=" \ libgeo-ip-perl \ arping \ snmp-mibs-downloader \ + snmptrapd \ libnsl2 \ openjdk-8-jdk " execute_cmd "apt install -y $server_dependencies" "Installing Pandora FMS Server dependencies" @@ -402,6 +454,7 @@ if [ "$SKIP_DATABASE_INSTALL" -eq '0' ] ; then """ | mysql -uroot &>> "$LOGFILE" export MYSQL_PWD=$DBROOTPASS + echo "INSTALL COMPONENT 'file://component_validate_password';" | mysql -uroot -P$DBPORT -h$DBHOST &>> "$LOGFILE" echo -en "${cyan}Creating Pandora FMS database...${reset}" echo "create database $DBNAME" | mysql -uroot -P$DBPORT -h$DBHOST check_cmd_status "Error creating database $DBNAME, is this an empty node? if you have a previus installation please contact with support." @@ -785,6 +838,10 @@ sed --follow-symlinks -i -e "s/^openssl_conf = openssl_init/#openssl_conf = open # Enable postfix systemctl enable postfix --now &>> "$LOGFILE" +# Disable snmptrapd +systemctl disable --now snmptrapd &>> "$LOGFILE" +systemctl disable --now snmptrapd.socket &>> "$LOGFILE" + #SSH banner [ "$(curl -s ifconfig.me)" ] && ipplublic=$(curl -s ifconfig.me) diff --git a/pandora_agents/pc/DEBIAN/control b/pandora_agents/pc/DEBIAN/control index cdbcc99cfe..ac23fd959f 100644 --- a/pandora_agents/pc/DEBIAN/control +++ b/pandora_agents/pc/DEBIAN/control @@ -4,7 +4,7 @@ Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: ÁRTICA ST +Maintainer: Pandora FMS Homepage: https://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/shellscript/linux/DEBIAN/control b/pandora_agents/shellscript/linux/DEBIAN/control index 55a5168f93..2ffdee57df 100755 --- a/pandora_agents/shellscript/linux/DEBIAN/control +++ b/pandora_agents/shellscript/linux/DEBIAN/control @@ -4,7 +4,7 @@ Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: ÁRTICA ST +Maintainer: Pandora FMS Homepage: http://pandorafms.org/ Depends: coreutils, perl Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/unix/DEBIAN/control b/pandora_agents/unix/DEBIAN/control index 6e5a9ccc64..7013fdec54 100644 --- a/pandora_agents/unix/DEBIAN/control +++ b/pandora_agents/unix/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-agent-unix -Version: 7.0NG.772-230719 +Version: 7.0NG.772-230727 Architecture: all Priority: optional Section: admin Installed-Size: 260 -Maintainer: ÁRTICA ST +Maintainer: Pandora FMS Homepage: http://pandorafms.org/ Depends: coreutils, perl, unzip Description: Pandora FMS agents are based on native languages in every platform: scripts that can be written in any language. It’s possible to reproduce any agent in any programming language and can be extended without difficulty the existing ones in order to cover aspects not taken into account up to the moment. These scripts are formed by modules that each one gathers a "chunk" of information. Thus, every agent gathers several "chunks" of information; this one is organized in a data set and stored in a single file, called data file. diff --git a/pandora_agents/unix/DEBIAN/make_deb_package.sh b/pandora_agents/unix/DEBIAN/make_deb_package.sh index 75850e3771..f8500d0a6a 100644 --- a/pandora_agents/unix/DEBIAN/make_deb_package.sh +++ b/pandora_agents/unix/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.772-230719" +pandora_version="7.0NG.772-230727" echo "Test if you has the tools for to make the packages." whereis dpkg-deb | cut -d":" -f2 | grep dpkg-deb > /dev/null diff --git a/pandora_agents/unix/Darwin/dmg/files/pandorafms_uninstall/PandoraFMS agent uninstaller.app/Contents/Info.plist b/pandora_agents/unix/Darwin/dmg/files/pandorafms_uninstall/PandoraFMS agent uninstaller.app/Contents/Info.plist index 4ee8965fef..e7c5fa5a91 100644 --- a/pandora_agents/unix/Darwin/dmg/files/pandorafms_uninstall/PandoraFMS agent uninstaller.app/Contents/Info.plist +++ b/pandora_agents/unix/Darwin/dmg/files/pandorafms_uninstall/PandoraFMS agent uninstaller.app/Contents/Info.plist @@ -6,7 +6,7 @@ CFBundleIdentifier com.pandorafms.pandorafms_uninstall CFBundleVersion 7.0NG.772 - CFBundleGetInfoString 7.0NG.772 Pandora FMS Agent uninstaller for MacOS by Artica ST on Aug 2020 + CFBundleGetInfoString 7.0NG.772 Pandora FMS on Aug 2020 CFBundleShortVersionString 7.0NG.772 NSPrincipalClassNSApplication diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 37f16c658f..23c6555256 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -1031,7 +1031,7 @@ my $Sem = undef; my $ThreadSem = undef; use constant AGENT_VERSION => '7.0NG.772'; -use constant AGENT_BUILD => '230719'; +use constant AGENT_BUILD => '230727'; # Agent log default file size maximum and instances use constant DEFAULT_MAX_LOG_SIZE => 600000; diff --git a/pandora_agents/unix/pandora_agent.redhat.spec b/pandora_agents/unix/pandora_agent.redhat.spec index be1df542a1..f665c4ae0c 100644 --- a/pandora_agents/unix/pandora_agent.redhat.spec +++ b/pandora_agents/unix/pandora_agent.redhat.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.772 -%define release 230719 +%define release 230727 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent.spec b/pandora_agents/unix/pandora_agent.spec index 1713a34f17..4b18f27d76 100644 --- a/pandora_agents/unix/pandora_agent.spec +++ b/pandora_agents/unix/pandora_agent.spec @@ -4,7 +4,7 @@ %global __os_install_post %{nil} %define name pandorafms_agent_linux %define version 7.0NG.772 -%define release 230719 +%define release 230727 Summary: Pandora FMS Linux agent, PERL version Name: %{name} diff --git a/pandora_agents/unix/pandora_agent_installer b/pandora_agents/unix/pandora_agent_installer index 90b464d570..fef5956bf4 100755 --- a/pandora_agents/unix/pandora_agent_installer +++ b/pandora_agents/unix/pandora_agent_installer @@ -10,7 +10,7 @@ # ********************************************************************** PI_VERSION="7.0NG.772" -PI_BUILD="230719" +PI_BUILD="230727" OS_NAME=`uname -s` FORCE=0 @@ -541,8 +541,17 @@ install () { then echo "Define 'pandora_agent=\"YES\"' in /etc/rc.conf to enable the daemon." else - echo "Check your startup configuration to be sure Pandora FMS Agent is ready " - echo "to start automatically when system restarts": + # Enable startup service + if [ `command -v systemctl` ] + then + systemctl enable pandora_agent_daemon + elif [ `command -v chkconfig` ] + then + chkconfig pandora_agent_daemon on + else + echo "Check your startup configuration to be sure Pandora FMS Agent is ready " + echo "to start automatically when system restarts": + fi fi # Restore the daemon script diff --git a/pandora_agents/win32/installer/pandora.mpi b/pandora_agents/win32/installer/pandora.mpi index a147da9939..4f843bd95f 100644 --- a/pandora_agents/win32/installer/pandora.mpi +++ b/pandora_agents/win32/installer/pandora.mpi @@ -186,7 +186,7 @@ UpgradeApplicationID {} Version -{230719} +{230727} ViewReadme {Yes} diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 8172d41f25..5cd8134ac4 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -30,7 +30,7 @@ using namespace Pandora; using namespace Pandora_Strutils; #define PATH_SIZE _MAX_PATH+1 -#define PANDORA_VERSION ("7.0NG.772 Build 230719") +#define PANDORA_VERSION ("7.0NG.772 Build 230727") string pandora_path; string pandora_dir; diff --git a/pandora_agents/win32/versioninfo.rc b/pandora_agents/win32/versioninfo.rc index 3878d891d0..378a849c43 100644 --- a/pandora_agents/win32/versioninfo.rc +++ b/pandora_agents/win32/versioninfo.rc @@ -6,12 +6,12 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Artica ST" + VALUE "CompanyName", "Pandora FMS" VALUE "FileDescription", "Pandora FMS Agent for Windows Platform" - VALUE "LegalCopyright", "Artica ST" + VALUE "LegalCopyright", "Pandora FMS" VALUE "OriginalFilename", "PandoraAgent.exe" VALUE "ProductName", "Pandora FMS Windows Agent" - VALUE "ProductVersion", "(7.0NG.772(Build 230719))" + VALUE "ProductVersion", "(7.0NG.772(Build 230727))" VALUE "FileVersion", "1.0.0.0" END END diff --git a/pandora_console/DEBIAN/control b/pandora_console/DEBIAN/control index 964bb752d0..f2018f1954 100644 --- a/pandora_console/DEBIAN/control +++ b/pandora_console/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-console -Version: 7.0NG.772-230719 +Version: 7.0NG.772-230727 Architecture: all Priority: optional Section: admin Installed-Size: 42112 -Maintainer: Artica ST +Maintainer: Pandora FMS Homepage: https://pandorafms.com/ Depends: php, php-snmp, php-gd, php-mysqlnd, php-db, php-xmlrpc, php-curl, graphviz, dbconfig-common, php-ldap, mysql-client | virtual-mysql-client, php-xmlrpc, php-zip, php-mbstring Description: Pandora FMS is an Open Source monitoring tool. It monitor your systems and applications, and allows you to control the status of any element of them. The web console is the graphical user interface (GUI) to manage the pool and to generate reports and graphs from the Pandora FMS monitoring process. diff --git a/pandora_console/DEBIAN/make_deb_package.sh b/pandora_console/DEBIAN/make_deb_package.sh index 5342ae5725..c50c6b47ce 100644 --- a/pandora_console/DEBIAN/make_deb_package.sh +++ b/pandora_console/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.772-230719" +pandora_version="7.0NG.772-230727" package_pear=0 package_pandora=1 @@ -163,7 +163,7 @@ if [ $package_pear -eq 1 ] then echo "Make the package \"php-xml-rpc\"." cd temp_package - dh-make-pear --maintainer "ÁRTICA ST " XML_RPC + dh-make-pear --maintainer "Pandora FMS " XML_RPC cd php-xml-rpc-* dpkg-buildpackage -rfakeroot cd .. diff --git a/pandora_console/composer.lock b/pandora_console/composer.lock index d7a05579a9..cf6f9f2502 100644 --- a/pandora_console/composer.lock +++ b/pandora_console/composer.lock @@ -609,7 +609,7 @@ } ], "description": "PHP library for ChartJS", - "homepage": "https://artica.es/", + "homepage": "https://pandorafms.com/", "keywords": [ "chartjs", "graph", diff --git a/pandora_console/extras/mr/65.sql b/pandora_console/extras/mr/65.sql index 259a6848dc..31e221f3b0 100644 --- a/pandora_console/extras/mr/65.sql +++ b/pandora_console/extras/mr/65.sql @@ -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); diff --git a/pandora_console/general/header.php b/pandora_console/general/header.php index af9e16d288..36090b9446 100644 --- a/pandora_console/general/header.php +++ b/pandora_console/general/header.php @@ -233,11 +233,8 @@ echo sprintf('
', $menuTypeClass); $header_autorefresh = ''; $header_autorefresh_counter = ''; - if ($config['legacy_vc'] - || ($_GET['sec2'] !== 'operation/visual_console/render_view') - || (($_GET['sec2'] !== 'operation/visual_console/render_view') - && $config['legacy_vc']) - ) { + + if (($_GET['sec2'] !== 'operation/visual_console/render_view')) { if ($autorefresh_list !== null && array_search($_GET['sec2'], $autorefresh_list) !== false ) { diff --git a/pandora_console/godmode/agentes/agent_manager.php b/pandora_console/godmode/agentes/agent_manager.php index b161b7ff6d..c1a14a31f5 100644 --- a/pandora_console/godmode/agentes/agent_manager.php +++ b/pandora_console/godmode/agentes/agent_manager.php @@ -212,7 +212,7 @@ $groups = users_get_groups($config['id_user'], 'AR', false); // Get modules. $modules = db_get_all_rows_sql( 'SELECT id_agente_modulo as id_module, nombre as name FROM tagente_modulo - WHERE id_agente = '.$id_parent + WHERE id_agente = '.$id_agente ); $modules_values = []; $modules_values[0] = __('Any'); diff --git a/pandora_console/godmode/agentes/planned_downtime.list.php b/pandora_console/godmode/agentes/planned_downtime.list.php index a9a65bc834..959db70ed6 100755 --- a/pandora_console/godmode/agentes/planned_downtime.list.php +++ b/pandora_console/godmode/agentes/planned_downtime.list.php @@ -89,7 +89,7 @@ if (is_ajax() === true) { [ 'id' => 'agent_modules_affected_planned_downtime', 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'godmode/agentes/planned_downtime.list', diff --git a/pandora_console/godmode/category/category.php b/pandora_console/godmode/category/category.php index 9872a002f5..46095b6efb 100755 --- a/pandora_console/godmode/category/category.php +++ b/pandora_console/godmode/category/category.php @@ -184,7 +184,7 @@ if (empty($result) === false) { ] ).'  '; $data[1] .= ''.html_print_image( - 'images/delet.svg', + 'images/delete.svg', true, [ 'title' => __('Delete'), diff --git a/pandora_console/godmode/groups/tactical.php b/pandora_console/godmode/groups/tactical.php index 067bed45be..0b09cbc789 100644 --- a/pandora_console/godmode/groups/tactical.php +++ b/pandora_console/godmode/groups/tactical.php @@ -187,7 +187,7 @@ try { [ 'id' => 'list_agents_tactical', 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columnNames, 'return' => true, diff --git a/pandora_console/godmode/massive/massive_delete_agents.php b/pandora_console/godmode/massive/massive_delete_agents.php index 5bb84b62be..1dc6397cc6 100755 --- a/pandora_console/godmode/massive/massive_delete_agents.php +++ b/pandora_console/godmode/massive/massive_delete_agents.php @@ -189,6 +189,14 @@ echo get_table_inputs_masive_agents($params); if (is_metaconsole() === true || is_management_allowed() === true) { attachActionButton('delete', 'delete', '100%', false, $SelectAction); +} else { + html_print_action_buttons( + '', + [ + 'right_content' => $SelectAction, + 'class' => 'pdd_t_15px_important pdd_b_15px_important', + ] + ); } echo ''; diff --git a/pandora_console/godmode/menu.php b/pandora_console/godmode/menu.php index 3d04b230b0..3f8ade2b1a 100644 --- a/pandora_console/godmode/menu.php +++ b/pandora_console/godmode/menu.php @@ -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,15 +79,97 @@ 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'); + } - if ((bool) check_acl($config['id_user'], 0, 'RW') === true - || (bool) check_acl($config['id_user'], 0, 'RM') === true - || (bool) check_acl($config['id_user'], 0, 'PM') === true - ) { - enterprise_hook('console_task_menu'); + $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 + || (bool) check_acl($config['id_user'], 0, 'RM') === true + || (bool) check_acl($config['id_user'], 0, 'PM') === true + ) { + enterprise_hook('console_task_menu'); + } } } @@ -502,9 +585,13 @@ if ($access_console_node === true) { $sub2[$extmenu['sec2']]['refr'] = 0; } else { if (is_array($extmenu) === true && array_key_exists('fatherId', $extmenu) === true) { - if (strlen($extmenu['fatherId']) > 0) { + if (empty($extmenu['fatherId']) === false + && strlen($extmenu['fatherId']) > 0 + ) { if (array_key_exists('subfatherId', $extmenu) === true) { - if (strlen($extmenu['subfatherId']) > 0) { + if (empty($extmenu['subfatherId']) === false + && strlen($extmenu['subfatherId']) > 0 + ) { $menu_godmode[$extmenu['fatherId']]['sub'][$extmenu['subfatherId']]['sub2'][$extmenu['sec2']]['text'] = __($extmenu['name']); $menu_godmode[$extmenu['fatherId']]['sub'][$extmenu['subfatherId']]['sub2'][$extmenu['sec2']]['id'] = str_replace(' ', '_', $extmenu['name']); $menu_godmode[$extmenu['fatherId']]['sub'][$extmenu['subfatherId']]['sub2'][$extmenu['sec2']]['refr'] = 0; diff --git a/pandora_console/godmode/reporting/graphs.php b/pandora_console/godmode/reporting/graphs.php index 6e66c886fb..1a5fbb4283 100644 --- a/pandora_console/godmode/reporting/graphs.php +++ b/pandora_console/godmode/reporting/graphs.php @@ -488,14 +488,38 @@ if (!empty($graphs)) { true ); $ActionButtons[] = ''; + + $offset = (int) get_parameter('offset', 0); + $block_size = (int) $config['block_size']; + + $tablePagination = ui_pagination( + count($graphs), + false, + $offset, + $block_size, + true, + 'offset', + false + ); } // FALTA METER EL PRINT TABLE. html_print_table($table); - html_print_action_buttons( - implode('', $ActionButtons), - ['type' => 'form_action'] - ); + + if (is_metaconsole() === true) { + html_print_action_buttons( + implode('', $ActionButtons), + ['type' => 'form_action'] + ); + } else { + html_print_action_buttons( + implode('', $ActionButtons), + [ + 'type' => 'form_action', + 'right_content' => $tablePagination, + ] + ); + } } echo '
'; diff --git a/pandora_console/godmode/reporting/reporting_builder.item_editor.php b/pandora_console/godmode/reporting/reporting_builder.item_editor.php index 4a629c1090..397e533366 100755 --- a/pandora_console/godmode/reporting/reporting_builder.item_editor.php +++ b/pandora_console/godmode/reporting/reporting_builder.item_editor.php @@ -6720,6 +6720,8 @@ function chooseType() { $("#row_agent").show(); $("#row_module").show(); $("#row_historical_db_check").hide(); + period_set_value($("#hidden-period").attr('class'), 3600); + $("#row_period").find('select').val('3600').trigger('change'); break; case 'SLA_monthly': diff --git a/pandora_console/godmode/reporting/reporting_builder.php b/pandora_console/godmode/reporting/reporting_builder.php index d00e70474d..00bc80f234 100755 --- a/pandora_console/godmode/reporting/reporting_builder.php +++ b/pandora_console/godmode/reporting/reporting_builder.php @@ -116,10 +116,13 @@ if (!$report_r && !$report_w && !$report_m) { } require_once $config['homedir'].'/include/functions_reports.php'; +require_once $config['homedir'].'/godmode/wizards/DiscoveryTaskList.class.php'; // Load enterprise extensions. enterprise_include('operation/reporting/custom_reporting.php'); enterprise_include_once('include/functions_metaconsole.php'); +enterprise_include_once('include/functions_tasklist.php'); +enterprise_include_once('include/functions_cron.php'); @@ -782,7 +785,7 @@ switch ($action) { ''.__('Filters').'', 'filter_form', '', - false, + true, false, '', 'white-box-content', @@ -1251,7 +1254,12 @@ switch ($action) { array_push($table->data, $data); } - html_print_table($table); + $reports_table = '
'; + $reports_table .= ''.__('Reports').''; + $reports_table .= html_print_table($table, true); + $reports_table .= '
'; + echo $reports_table; + $tablePagination = ui_pagination( $total_reports, $url, @@ -1259,7 +1267,7 @@ switch ($action) { $pagination, true, 'offset', - false, + false ); } else { ui_print_info_message( @@ -1270,6 +1278,21 @@ switch ($action) { ); } + $discovery_tasklist = new DiscoveryTaskList(); + $report_task_data = $discovery_tasklist->showListConsoleTask(true); + + if (is_array($report_task_data) === true || strpos($report_task_data, 'class="nf"') === false) { + $task_table = '
'; + $task_table .= ''.__('Report tasks'); + $task_table .= ui_print_help_tip(__('To schedule a report, do it from the editing view of each report.'), true); + $task_table .= '
'; + $task_table .= $report_task_data; + $task_table .= '
'; + echo $task_table; + } else { + ui_print_info_message($report_task_data.__('To schedule a report, do it from the editing view of each report.')); + } + if (check_acl($config['id_user'], 0, 'RW') || check_acl($config['id_user'], 0, 'RM') ) { diff --git a/pandora_console/godmode/reporting/visual_console_builder.php b/pandora_console/godmode/reporting/visual_console_builder.php index 740b97708a..9988704695 100755 --- a/pandora_console/godmode/reporting/visual_console_builder.php +++ b/pandora_console/godmode/reporting/visual_console_builder.php @@ -837,12 +837,6 @@ $buttons['wizard'] = [ 'active' => false, 'text' => '
'.html_print_image('images/wizard@svg.svg', true, ['title' => __('Wizard'), 'class' => 'invert_filter']).'', ]; -if ($config['legacy_vc']) { - $buttons['editor'] = [ - 'active' => false, - 'text' => ''.html_print_image('images/builder@svg.svg', true, ['title' => __('Builder'), 'class' => 'invert_filter']).'', - ]; -} $buttons['view'] = [ 'active' => false, diff --git a/pandora_console/godmode/servers/discovery.php b/pandora_console/godmode/servers/discovery.php index 3df3342f52..9af4343a84 100755 --- a/pandora_console/godmode/servers/discovery.php +++ b/pandora_console/godmode/servers/discovery.php @@ -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( @@ -161,7 +167,7 @@ if ($classname_selected === null) { $wiz_data = []; foreach ($classes as $classpath) { if (is_reporting_console_node() === true) { - if ($classpath !== '/var/www/html/pandora_console/godmode/wizards/DiscoveryTaskList.class.php') { + if ($classpath !== $config['homedir'].'/godmode/wizards/DiscoveryTaskList.class.php') { continue; } } @@ -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) { diff --git a/pandora_console/godmode/servers/plugin.php b/pandora_console/godmode/servers/plugin.php index 04b622e312..315702528e 100644 --- a/pandora_console/godmode/servers/plugin.php +++ b/pandora_console/godmode/servers/plugin.php @@ -560,7 +560,14 @@ if (empty($create) === false || empty($view) === false) { // $data[0] = html_print_div(['id' => 'command_preview', 'class' => 'mono'], true); $data[0] = html_print_label_input_block( __('Command preview'), - html_print_div(['id' => 'command_preview', 'class' => 'mono'], true) + html_print_div( + [ + 'id' => 'command_preview', + 'class' => 'mono', + 'style' => 'max-width: 1050px;overflow-wrap: break-word;', + ], + true + ) ); $table->data['plugin_preview_inputs'] = $data; $table->colspan['plugin_preview_inputs'][0] = 2; diff --git a/pandora_console/godmode/servers/servers.build_table.php b/pandora_console/godmode/servers/servers.build_table.php index 8cb64950d3..35cd540e6a 100644 --- a/pandora_console/godmode/servers/servers.build_table.php +++ b/pandora_console/godmode/servers/servers.build_table.php @@ -101,6 +101,13 @@ foreach ($servers as $server) { } } +$ext = ''; + +// Check for any data-type server present in servers list. If none, enable server access for first server. +if (array_search('data', array_column($servers, 'type')) === false) { + $ext = '_server'; +} + foreach ($servers as $server) { $data = []; @@ -185,14 +192,12 @@ foreach ($servers as $server) { $data[7] = ui_print_timestamp($server['keepalive'], true); - - $ext = '_server'; - if ($server['type'] != 'data') { - $ext = ''; + if ($server['type'] === 'data') { + $ext = '_server'; } $safe_server_name = servers_get_name($server['id_server']); - if (($server['type'] == 'data' || $server['type'] == 'enterprise satellite')) { + if (($ext === '_server' || $server['type'] == 'enterprise satellite')) { if (servers_check_remote_config($safe_server_name.$ext) && enterprise_installed()) { $names_servers[$safe_server_name] = true; } else { @@ -253,9 +258,19 @@ foreach ($servers as $server) { ); $data[8] .= ''; - if (($names_servers[$safe_server_name] === true) && ($server['type'] === 'data' || $server['type'] === 'enterprise satellite')) { + if (($names_servers[$safe_server_name] === true) && ($ext === '_server' || $server['type'] === 'enterprise satellite')) { $data[8] .= ''; - $data[8] .= ''; + $data[8] .= html_print_image( + 'images/agents@svg.svg', + true, + [ + 'title' => __('Manage server conf'), + 'class' => 'main_menu_icon invert_filter', + ] + ); + $data[8] .= ''; + + $data[8] .= ''; $data[8] .= html_print_image( 'images/remote-configuration@svg.svg', true, @@ -288,6 +303,8 @@ foreach ($servers as $server) { unset($data[8]); } + $ext = ''; + array_push($table->data, $data); } diff --git a/pandora_console/godmode/setup/performance.php b/pandora_console/godmode/setup/performance.php index 0cd6c53d2d..bf56eb2e43 100644 --- a/pandora_console/godmode/setup/performance.php +++ b/pandora_console/godmode/setup/performance.php @@ -545,23 +545,8 @@ $table->data[6][0] = html_print_label_input_block( ) ); -$table->data[6][1] = html_print_label_input_block( - __('Max. days before delete old network matrix data'), - html_print_input( - [ - 'type' => 'number', - 'size' => 5, - 'max' => $performance_variables_control['delete_old_network_matrix']->max, - 'name' => 'delete_old_network_matrix', - 'value' => $config['delete_old_network_matrix'], - 'return' => true, - 'min' => $performance_variables_control['delete_old_network_matrix']->min, - ] - ) -); - if (enterprise_installed()) { - $table->data[7][0] = html_print_label_input_block( + $table->data[6][1] = html_print_label_input_block( __('Max. days before delete inventory data'), html_print_input_text( 'inventory_purge', diff --git a/pandora_console/godmode/setup/setup_general.php b/pandora_console/godmode/setup/setup_general.php index cd7594c017..aa55893d11 100644 --- a/pandora_console/godmode/setup/setup_general.php +++ b/pandora_console/godmode/setup/setup_general.php @@ -757,6 +757,15 @@ $table->data[$i++][] = html_print_label_input_block( ] ) ); +$table->data[$i][] = html_print_label_input_block( + __('Show experimental features'), + html_print_checkbox_switch( + 'show_experimental_features', + 1, + $config['show_experimental_features'], + true + ) +); echo '
'; diff --git a/pandora_console/godmode/setup/setup_visuals.php b/pandora_console/godmode/setup/setup_visuals.php index 96856a2f32..a7b64a67d7 100755 --- a/pandora_console/godmode/setup/setup_visuals.php +++ b/pandora_console/godmode/setup/setup_visuals.php @@ -1344,17 +1344,6 @@ $table_vc->style[0] = 'font-weight: bold'; $table_vc->size[0] = '50%'; $table_vc->data = []; -// Remove when the new view reaches rock solid stability. -$table_vc->data[$row][] = html_print_label_input_block( - __('Legacy Visual Console View'), - html_print_checkbox_switch( - 'legacy_vc', - 1, - (bool) $config['legacy_vc'], - true - ) -); - $table_vc->data[$row][] = html_print_label_input_block( __('Default cache expiration'), html_print_extended_select_for_time( @@ -1372,7 +1361,6 @@ $table_vc->data[$row][] = html_print_label_input_block( $intervals ) ); -$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Default interval for refresh on Visual Console'), @@ -1388,6 +1376,7 @@ $table_vc->data[$row][] = html_print_label_input_block( false ) ); +$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Type of view of visual consoles'), @@ -1401,12 +1390,12 @@ $table_vc->data[$row][] = html_print_label_input_block( true ) ); -$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Number of favorite visual consoles to show in the menu'), "" ); +$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Default line thickness for the Visual Console'), @@ -1419,7 +1408,6 @@ $table_vc->data[$row][] = html_print_label_input_block( true ) ); -$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Lock screen orientation when viewing on mobile devices'), @@ -1430,6 +1418,7 @@ $table_vc->data[$row][] = html_print_label_input_block( true ) ); +$row++; $table_vc->data[$row][] = html_print_label_input_block( __('Display item frame on alert triggered'), diff --git a/pandora_console/godmode/update_manager/update_manager.history.php b/pandora_console/godmode/update_manager/update_manager.history.php index e827951e88..7caab40f8b 100644 --- a/pandora_console/godmode/update_manager/update_manager.history.php +++ b/pandora_console/godmode/update_manager/update_manager.history.php @@ -50,7 +50,7 @@ try { [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'include/ajax/update_manager', diff --git a/pandora_console/godmode/wizards/Applications.class.php b/pandora_console/godmode/wizards/Applications.class.php new file mode 100644 index 0000000000..2237fdbe73 --- /dev/null +++ b/pandora_console/godmode/wizards/Applications.class.php @@ -0,0 +1,221 @@ +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 '
*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'
'; + } + + 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; + } + } + + +} diff --git a/pandora_console/godmode/wizards/Cloud.class.php b/pandora_console/godmode/wizards/Cloud.class.php new file mode 100644 index 0000000000..4664b1a566 --- /dev/null +++ b/pandora_console/godmode/wizards/Cloud.class.php @@ -0,0 +1,661 @@ +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 '
*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'
'; + } + + 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 = '
'; + $link_to_cs .= __('Manage accounts').''; + } + + $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; + } + } + + +} diff --git a/pandora_console/godmode/wizards/Custom.class.php b/pandora_console/godmode/wizards/Custom.class.php new file mode 100644 index 0000000000..41a177b3e3 --- /dev/null +++ b/pandora_console/godmode/wizards/Custom.class.php @@ -0,0 +1,160 @@ +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 '
*'.__('All company names used here are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.').'
'; + 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; + } + } + + +} diff --git a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php index e659f85e9e..1c7ffe5526 100644 --- a/pandora_console/godmode/wizards/DiscoveryTaskList.class.php +++ b/pandora_console/godmode/wizards/DiscoveryTaskList.class.php @@ -129,6 +129,11 @@ class DiscoveryTaskList extends HTML } $delete_console_task = (bool) get_parameter('delete_console_task'); + $report_task = (bool) get_parameter('report_task', 0); + if ($report_task === true) { + $this->url = ui_get_full_url('index.php?sec=reporting&sec2=godmode/reporting/reporting_builder'); + } + if ($delete_console_task === true) { return $this->deleteConsoleTask(); } @@ -163,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) { @@ -287,6 +295,10 @@ class DiscoveryTaskList extends HTML } $id_console_task = (int) get_parameter('id_console_task'); + $report_task = (bool) get_parameter('report_task', 0); + if ($report_task === true) { + $this->url = ui_get_full_url('index.php?sec=reporting&sec2=godmode/reporting/reporting_builder'); + } if ($id_console_task != null) { // -------------------------------- @@ -352,6 +364,10 @@ class DiscoveryTaskList extends HTML } $id_console_task = (int) get_parameter('id_console_task'); + $report_task = (bool) get_parameter('report_task', 0); + if ($report_task === true) { + $this->url = ui_get_full_url('index.php?sec=reporting&sec2=godmode/reporting/reporting_builder'); + } if ($id_console_task > 0) { $result = db_process_sql_update( @@ -505,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; @@ -531,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( ',', @@ -539,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 ) ); } @@ -658,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] = ''; $data[9] .= html_print_image( 'images/web@groups.svg', @@ -999,13 +1050,24 @@ class DiscoveryTaskList extends HTML ).''; } } else { + $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] .= ''.html_print_image( 'images/edit.svg', true, @@ -1069,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 ''; @@ -1096,9 +1158,9 @@ class DiscoveryTaskList extends HTML * * @return boolean Success or not. */ - public function showListConsoleTask() + public function showListConsoleTask($report_task=false) { - return enterprise_hook('tasklist_showListConsoleTask', [$this]); + return enterprise_hook('tasklist_showListConsoleTask', [$this, $report_task]); } @@ -1227,7 +1289,7 @@ class DiscoveryTaskList extends HTML ($task['status'] < 0) ? 100 : $task['status'], 150, 150, - '#3A3A3A', + '#14524f', '%', '', '#ececec', @@ -1297,7 +1359,7 @@ class DiscoveryTaskList extends HTML $task['stats']['c_network_percent'], 150, 150, - '#3A3A3A', + '#14524f', '%', '', '#ececec', @@ -1340,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'; @@ -1405,6 +1467,65 @@ class DiscoveryTaskList extends HTML $table->data[$i][1] = ''; $table->data[$i][1] .= ($total - $agents); $table->data[$i++][1] .= ''; + } 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] = ''.__('Summary').' '.$countSummary.''; + $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] = ''.__('Summary').''; + $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) { @@ -1466,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 = ''; @@ -1859,7 +1980,11 @@ class DiscoveryTaskList extends HTML if ($task['status'] <= 0 && empty($task['summary']) === false ) { - $status = __('Done'); + if ($task['status'] == -2) { + $status = __('Failed'); + } else { + $status = __('Done'); + } } else if ($task['utimestamp'] == 0 && empty($task['summary']) ) { diff --git a/pandora_console/godmode/wizards/ManageExtensions.class.php b/pandora_console/godmode/wizards/ManageExtensions.class.php new file mode 100644 index 0000000000..03b1bdee7b --- /dev/null +++ b/pandora_console/godmode/wizards/ManageExtensions.class.php @@ -0,0 +1,1054 @@ +ajaxController = $config['homedir'].'/include/ajax/manage_extensions.ajax'; + $this->url = ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=magextensions' + ); + } + + + /** + * Checks if target method is available to be called using AJAX. + * + * @param string $method Target method. + * + * @return boolean True allowed, false not. + */ + public function ajaxMethod($method) + { + // Check access. + check_login(); + + return in_array($method, $this->AJAXMethods); + } + + + /** + * Implements load method. + * + * @return mixed Skeleton for button. + */ + public function load() + { + return [ + 'icon' => $this->icon, + 'label' => $this->label, + 'url' => $this->url, + + ]; + + } + + + /** + * Generates a JSON error. + * + * @param string $msg Error message. + * + * @return void + */ + public function errorAjax(string $msg) + { + echo json_encode( + ['error' => $msg] + ); + } + + + /** + * Implements run method. + * + * @return void + */ + public function run() + { + global $config; + // Load styles. + parent::run(); + + $uploadDisco = get_parameter('upload_disco', ''); + $action = get_parameter('action', ''); + $shortName = get_parameter('short_name', ''); + + if (empty($uploadDisco) === false) { + if ($_FILES['file']['error'] == 0) { + $result = $this->uploadExtension($_FILES['file']); + if ($result === true) { + ui_print_success_message( + __('Uploaded extension') + ); + } else { + if (is_string($result)) { + echo $this->error($result); + } else { + echo $this->error(__('Failed to upload extension')); + } + } + } else { + echo $this->error(__('Failed to upload extension')); + } + } + + if (empty($action) === false && empty($shortName) === false) { + switch ($action) { + case 'delete': + $result = $this->uninstallExtension($shortName); + if ($result === true) { + ui_print_success_message( + __('Deleted extension') + ); + } else { + echo $this->error(__('Fail delete extension')); + } + + case 'sync_server': + $syncAction = get_parameter('sync_action', ''); + if ($syncAction === 'refresh') { + $installationFolder = $config['homedir'].'/'.$this->path.'/'.$shortName; + $result = $this->copyExtensionToServer($installationFolder, $shortName); + if ($result === true) { + ui_print_success_message( + __('Extension folder created successfully') + ); + } else { + echo $this->error(__('Fail created extension folder')); + } + } + break; + + default: + continue; + } + } + + $this->prepareBreadcrum( + [ + [ + 'link' => ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery' + ), + 'label' => __('Discovery'), + ], + [ + 'link' => '', + 'label' => _('Manage disco packages'), + 'selected' => 1, + ], + ] + ); + + // Header. + ui_print_page_header( + __('Manage disco packages'), + '', + false, + '', + true, + '', + false, + '', + GENERIC_SIZE_TEXT, + '', + $this->printHeader(true) + ); + + $table = new stdClass(); + $table->width = '100%'; + $table->class = 'databox filters'; + $table->size = []; + $table->size[0] = '80%'; + $table->align[3] = 'right'; + $table->data = []; + $table->data[0][0] = html_print_label_input_block( + __('Load DISCO'), + html_print_div( + [ + 'id' => 'upload_file', + 'content' => html_print_input_file( + 'file', + true, + ['style' => 'width:100%'] + ), + 'class' => 'mrgn_top_15px', + ], + true + ) + ); + $table->data[0][3] = html_print_submit_button( + __('Upload DISCO'), + 'upload_button', + false, + [ + 'class' => 'sub ok float-right', + 'icon' => 'next', + ], + true + ); + + echo ''; + html_print_input_hidden('upload_disco', 1); + html_print_table($table); + echo '
'; + + echo '
'; + echo ''; + + echo ''; + ui_require_javascript_file('manage_extensions'); + try { + $columns = [ + 'name', + 'short_name', + 'section', + 'description', + 'version', + [ + 'text' => 'actions', + 'class' => 'flex flex-items-center', + ], + ]; + + $columnNames = [ + __('Name'), + __('Short name'), + __('Section'), + __('Description'), + __('Version'), + __('Actions'), + ]; + + // Load datatables user interface. + ui_print_datatable( + [ + 'id' => 'list_extensions', + 'class' => 'info_table', + 'style' => 'width: 99%', + 'dom_elements' => 'plfti', + 'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar', + 'columns' => $columns, + 'column_names' => $columnNames, + 'ajax_url' => $this->ajaxController, + 'ajax_data' => ['method' => 'getExtensionsInstalled'], + 'no_sortable_columns' => [-1], + 'order' => [ + 'field' => 'name', + 'direction' => 'asc', + ], + 'search_button_class' => 'sub filter float-right', + ] + ); + } catch (Exception $e) { + echo $e->getMessage(); + } + + } + + + /** + * Upload extension to server. + * + * @param array $disco File disco tu upload. + * + * @return boolean $result Of operation, true if is ok. + */ + private function uploadExtension($disco) + { + global $config; + if (substr($disco['name'], -6) !== '.disco') { + return false; + } + + $nameFile = str_replace('.disco', '.zip', $disco['name']); + $nameTempDir = $config['attachment_store'].'/downloads/'; + if (file_exists($nameTempDir) === false) { + mkdir($nameTempDir); + } + + $tmpPath = Files::tempdirnam( + $nameTempDir, + 'extensions_uploaded_' + ); + $result = move_uploaded_file($disco['tmp_name'], $tmpPath.'/'.$nameFile); + if ($result === true) { + $unzip = $this->unZip($tmpPath.'/'.$nameFile, $tmpPath); + if ($unzip === true) { + unlink($tmpPath.'/'.$nameFile); + db_process_sql_begin(); + $this->iniFile = parse_ini_file($tmpPath.'/discovery_definition.ini', true, INI_SCANNER_TYPED); + if ($this->iniFile === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return __('Failed to upload extension: Error while parsing dicovery_definition.ini'); + } + + $error = ExtensionsDiscovery::validateIni($this->iniFile); + if ($error !== false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return $error; + } + + $id = $this->installExtension(); + if ($id === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return false; + } + + $result = $this->autoLoadConfigExec($id); + if ($result === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return false; + } + + $result = $this->autoUpdateDefaultMacros($id); + if ($result === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return false; + } + + $nameFolder = $this->iniFile['discovery_extension_definition']['short_name']; + $installationFolder = $config['homedir'].'/'.$this->path.'/'.$nameFolder; + if (file_exists($installationFolder) === false) { + mkdir($installationFolder, 0777, true); + } else { + Files::rmrf($installationFolder, true); + } + + $result = Files::move($tmpPath, $installationFolder, true); + if ($result === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return false; + } + + $this->setPermissionfiles($installationFolder, $this->iniFile['discovery_extension_definition']['execution_file']); + $this->setPermissionfiles( + $installationFolder, + [ + $this->iniFile['discovery_extension_definition']['passencrypt_script'], + $this->iniFile['discovery_extension_definition']['passdecrypt_script'], + ] + ); + + $result = $this->copyExtensionToServer($installationFolder, $nameFolder); + if ($result === false) { + db_process_sql_rollback(); + Files::rmrf($tmpPath); + return false; + } + + Files::rmrf($tmpPath); + db_process_sql_commit(); + return true; + } + } else { + Files::rmrf($tmpPath); + return false; + } + } + + + /** + * Copy the extension folder into remote path server. + * + * @param string $path Path extension folder. + * @param string $nameFolder Name of extension folder. + * + * @return boolean Result of operation. + */ + public function copyExtensionToServer($path, $nameFolder) + { + global $config; + $filesToExclude = [ + 'discovery_definition.ini', + 'logo.png', + ]; + $serverPath = $config['remote_config'].'/discovery/'.$nameFolder; + if (file_exists($serverPath) === false) { + mkdir($serverPath, 0777, true); + } else { + Files::rmrf($serverPath, true); + } + + $result = $this->copyFolder($path, $serverPath, $filesToExclude); + $this->setPermissionfiles($serverPath, $this->iniFile['discovery_extension_definition']['execution_file']); + + return $result; + } + + + /** + * Copy from $source path to $destination + * + * @param string $source Initial folder path. + * @param string $destination Destination folder path. + * @param array $exclude Files to exlcude in copy. + * + * @return boolean Result of operation. + */ + public function copyFolder($source, $destination, $exclude=[]) + { + if (file_exists($destination) === false) { + mkdir($destination, 0777, true); + } + + $files = scandir($source); + foreach ($files as $file) { + if ($file !== '.' && $file !== '..') { + if (is_dir($source.'/'.$file)) { + $result = $this->copyFolder($source.'/'.$file, $destination.'/'.$file); + if ($result === false) { + return false; + } + } else { + if (in_array($file, $exclude) === false) { + $result = copy($source.'/'.$file, $destination.'/'.$file); + if ($result === false) { + return false; + } + } + } + } + } + + return true; + } + + + /** + * Delete extension from database and delete folder + * + * @param integer $shortName Short name app for delete. + * + * @return boolean Result of operation. + */ + private function uninstallExtension($shortName) + { + global $config; + + $result = db_process_sql_delete( + 'tdiscovery_apps', + ['short_name' => $shortName] + ); + + if ($result !== false) { + Files::rmrf($config['homedir'].'/'.$this->path.'/'.$shortName); + Files::rmrf($config['remote_config'].'/discovery/'.$shortName); + return true; + } else { + return false; + } + } + + + /** + * Load the basic information of the app into database. + * + * @return boolean Result of query. + */ + private function installExtension() + { + $exist = db_get_row_filter( + 'tdiscovery_apps', + [ + 'short_name' => $this->iniFile['discovery_extension_definition']['short_name'], + ] + ); + $version = $this->iniFile['discovery_extension_definition']['version']; + if ($version === null) { + $version = ''; + } + + $description = $this->iniFile['discovery_extension_definition']['description']; + if ($description === null) { + $description = ''; + } + + if ($exist === false) { + return db_process_sql_insert( + 'tdiscovery_apps', + [ + 'short_name' => $this->iniFile['discovery_extension_definition']['short_name'], + 'name' => io_safe_input($this->iniFile['discovery_extension_definition']['name']), + 'description' => io_safe_input($description), + 'section' => $this->iniFile['discovery_extension_definition']['section'], + 'version' => $version, + ] + ); + } else { + $result = db_process_sql_update( + 'tdiscovery_apps', + [ + 'name' => io_safe_input($this->iniFile['discovery_extension_definition']['name']), + 'description' => io_safe_input($description), + 'section' => $this->iniFile['discovery_extension_definition']['section'], + 'version' => $version, + ], + [ + 'short_name' => $this->iniFile['discovery_extension_definition']['short_name'], + ] + ); + + if ($result !== false) { + return $exist['id_app']; + } + } + } + + + /** + * Return all extension installed by ajax. + * + * @return void + */ + public function getExtensionsInstalled() + { + global $config; + + $data = []; + $start = get_parameter('start', 0); + $length = get_parameter('length', $config['block_size']); + $orderDatatable = get_datatable_order(true); + $pagination = ''; + $order = ''; + + try { + ob_start(); + + if (isset($orderDatatable)) { + $order = sprintf( + ' ORDER BY %s %s', + $orderDatatable['field'], + $orderDatatable['direction'] + ); + } + + if (isset($length) && $length > 0 + && isset($start) && $start >= 0 + ) { + $pagination = sprintf( + ' LIMIT %d OFFSET %d ', + $length, + $start + ); + } + + $sql = sprintf( + 'SELECT short_name, name, section, description, version + FROM tdiscovery_apps + %s %s', + $order, + $pagination + ); + + $data = db_get_all_rows_sql($sql); + + $sqlCount = sprintf( + 'SELECT short_name, name, section, description, version + FROM tdiscovery_apps + %s', + $order, + ); + + $count = db_get_num_rows($sqlCount); + + foreach ($data as $key => $row) { + $logo = $this->path.'/'.$row['short_name'].'/logo.png'; + if (file_exists($logo) === false) { + $logo = $this->defaultLogo; + } + + $logo = html_print_image($logo, true, ['style' => 'max-width: 30px; margin-right: 15px;']); + $data[$key]['name'] = $logo.io_safe_output($row['name']); + $data[$key]['short_name'] = $row['short_name']; + $data[$key]['description'] = io_safe_output($row['description']); + $data[$key]['version'] = $row['version']; + $data[$key]['actions'] = '
'; + $data[$key]['actions'] .= html_print_input_image( + 'button_delete', + 'images/delete.svg', + '', + '', + true, + [ + 'onclick' => 'if (!confirm(\''.__('Deleting this application will also delete all the discovery tasks using it. Do you want to delete it?').'\')) return false;', + 'class' => 'main_menu_icon invert_filter action_button_hidden', + ] + ); + $data[$key]['actions'] .= html_print_input_hidden('short_name', $row['short_name'], true); + $data[$key]['actions'] .= '
'; + if ($this->checkFolderConsole($row['short_name']) === true) { + $data[$key]['actions'] .= '
'; + $data[$key]['actions'] .= html_print_input_image( + 'button_refresh', + 'images/refresh@svg.svg', + '', + '', + true, + [ + 'onclick' => 'if (!confirm(\''.__('Are you sure you want to reapply?').'\')) return false;', + 'class' => 'main_menu_icon invert_filter action_button_hidden', + ] + ); + $data[$key]['actions'] .= html_print_input_hidden('sync_action', 'refresh', true); + $data[$key]['actions'] .= html_print_input_hidden('short_name', $row['short_name'], true); + $data[$key]['actions'] .= '
'; + } else { + $data[$key]['actions'] .= html_print_image( + 'images/error_red.png', + true, + [ + 'title' => __('The extension directory or .ini does not exist in console.'), + 'alt' => __('The extension directory or .ini does not exist in console.'), + 'class' => 'main_menu_icon invert_filter', + ], + ); + } + } + + if (empty($data) === true) { + $total = 0; + $data = []; + } else { + $total = $count; + } + + echo json_encode( + [ + 'data' => $data, + 'recordsTotal' => $total, + 'recordsFiltered' => $total, + ] + ); + // Capture output. + $response = ob_get_clean(); + } catch (Exception $e) { + echo json_encode(['error' => $e->getMessage()]); + exit; + } + + json_decode($response); + if (json_last_error() === JSON_ERROR_NONE) { + echo $response; + } else { + echo json_encode( + [ + 'success' => false, + 'error' => $response, + ] + ); + } + + exit; + } + + + /** + * Insert new the default values for extension. + * + * @param integer $id Id of extension. + * + * @return boolean Result of query. + */ + private function autoUpdateDefaultMacros($id) + { + $defaultValues = $this->iniFile['discovery_extension_definition']['default_value']; + + foreach ($defaultValues as $macro => $value) { + $sql = 'INSERT IGNORE INTO `tdiscovery_apps_tasks_macros` + (`id_task`, `macro`, `type`, `value`, `temp_conf`) + SELECT `id_rt`, "'.$macro.'", "custom", "'.(string) io_safe_input($value).'", "0" + FROM `trecon_task` + WHERE `id_app` = "'.$id.'";'; + $result = db_process_sql($sql); + if ($result === false) { + return false; + } + } + + $tempFiles = $this->iniFile['tempfile_confs']['file']; + foreach ($tempFiles as $macro => $value) { + $sql = 'UPDATE `tdiscovery_apps_tasks_macros` + SET `value` = "'.(string) io_safe_input($value).'" WHERE `id_task` + IN (SELECT `id_rt` FROM `trecon_task` WHERE `id_app` = "'.$id.'") AND `macro` = "'.$macro.'"'; + $result = db_process_sql($sql); + if ($result === false) { + return false; + } + + $sql = 'INSERT IGNORE INTO `tdiscovery_apps_tasks_macros` + (`id_task`, `macro`, `type`, `value`, `temp_conf`) + SELECT `id_rt`, "'.$macro.'", "custom", "'.(string) io_safe_input($value).'", "1" + FROM `trecon_task` + WHERE `id_app` = "'.$id.'";'; + $result = db_process_sql($sql); + if ($result === false) { + return false; + } + } + + return true; + } + + + /** + * Load the exec files in database + * + * @param integer $id Id of extension. + * + * @return boolean Result of query. + */ + private function autoLoadConfigExec($id) + { + $executionFiles = $this->iniFile['discovery_extension_definition']['execution_file']; + + foreach ($executionFiles as $key => $value) { + $exist = db_get_row_filter( + 'tdiscovery_apps_scripts', + [ + 'id_app' => $id, + 'macro' => $key, + ] + ); + if ($exist === false) { + $result = db_process_sql_insert( + 'tdiscovery_apps_scripts', + [ + 'id_app' => $id, + 'macro' => $key, + 'value' => io_safe_input($value), + ] + ); + if ($result === false) { + return false; + } + } else { + $result = db_process_sql_update( + 'tdiscovery_apps_scripts', + ['value' => io_safe_input($value)], + [ + 'id_app' => $id, + 'macro' => $key, + ] + ); + if ($result === false) { + return false; + } + } + } + + $execCommands = $this->iniFile['discovery_extension_definition']['exec']; + $result = db_process_sql_delete( + 'tdiscovery_apps_executions', + ['id_app' => $id] + ); + if ($result === false) { + return false; + } + + foreach ($execCommands as $key => $value) { + $result = db_process_sql_insert( + 'tdiscovery_apps_executions', + [ + 'id_app' => $id, + 'execution' => io_safe_input($value), + ] + ); + if ($result === false) { + return false; + } + } + + return true; + } + + + /** + * Check if exist folder extension in console. + * + * @param string $shortName Name of folder. + * + * @return boolean Return true if exist folder + */ + private function checkFolderConsole($shortName) + { + global $config; + + $folderPath = $config['homedir'].'/'.$this->path.'/'.$shortName; + $iniPath = $config['homedir'].'/'.$this->path.'/'.$shortName.'/discovery_definition.ini'; + if (file_exists($folderPath) === false || file_exists($iniPath) === false) { + return false; + } else { + return true; + } + } + + + /** + * Validate the ini name by ajax. + * + * @return void + */ + public function validateIniName() + { + global $config; + $uploadDisco = get_parameter('upload_disco', ''); + if (empty($uploadDisco) === false) { + if ($_FILES['file']['error'] == 0) { + $disco = $_FILES['file']; + } else { + echo json_encode(['success' => false, 'message' => 'Failed to upload extension']); + return; + } + } + + if (substr($disco['name'], -6) !== '.disco') { + echo json_encode(['success' => false, 'message' => 'Failed to upload extension']); + return; + } + + $nameFile = str_replace('.disco', '.zip', $disco['name']); + $nameTempDir = $config['attachment_store'].'/downloads/'; + if (file_exists($nameTempDir) === false) { + mkdir($nameTempDir); + } + + $tmpPath = Files::tempdirnam( + $nameTempDir, + 'extensions_uploaded_' + ); + $result = move_uploaded_file($disco['tmp_name'], $tmpPath.'/'.$nameFile); + if ($result === true) { + $unzip = $this->unZip($tmpPath.'/'.$nameFile, $tmpPath, 'discovery_definition.ini'); + if ($unzip === true) { + unlink($tmpPath.'/'.$nameFile); + $this->iniFile = parse_ini_file($tmpPath.'/discovery_definition.ini', true, INI_SCANNER_TYPED); + if ($this->iniFile === false) { + Files::rmrf($tmpPath); + echo json_encode(['success' => false, 'message' => __('Failed to upload extension: Error while parsing dicovery_definition.ini')]); + return; + } + + $message = false; + $shortName = $this->iniFile['discovery_extension_definition']['short_name']; + if (strpos($shortName, 'pandorafms.') === 0) { + $message = __('The \'short_name\' starting with \'pandorafms.\' is reserved for Pandora FMS applications. If this is not an official Pandora FMS application, consider changing the \'short_name\'. Do you want to continue?'); + } + + $exist = db_get_row_filter( + 'tdiscovery_apps', + ['short_name' => $shortName] + ); + + if ($exist !== false) { + $message = __('There is another application with the same \'short_name\': \'%s\'. Do you want to overwrite the application and all of its contents?', $shortName); + } + + if ($message !== false) { + echo json_encode( + [ + 'success' => true, + 'warning' => true, + 'message' => $message, + ] + ); + } else { + echo json_encode(['success' => true]); + } + + Files::rmrf($tmpPath); + return; + } + } else { + Files::rmrf($tmpPath); + echo json_encode(['success' => false, 'message' => __('Failed to upload extension')]); + return; + } + } + + + /** + * Return all extensions from section. + * + * @param string $section Section to filter. + * + * @return array List of sections. + */ + static public function getExtensionBySection($section) + { + return db_get_all_rows_filter( + 'tdiscovery_apps', + ['section' => $section] + ); + } + + + /** + * Set execution permission in folder items and subfolders. + * + * @param string $path Array of files to apply permissions. + * @param array $filter Array of files for apply permission only. + * + * @return void + */ + private function setPermissionfiles($path, $filter=false) + { + global $config; + + if ($filter !== false && is_array($filter) === true) { + foreach ($filter as $key => $file) { + if (substr($file, 0, 1) !== '/') { + $file = $path.'/'.$file; + } + + chmod($file, 0777); + } + } else { + chmod($path, 0777); + + if (is_dir($path)) { + $items = scandir($path); + foreach ($items as $item) { + if ($item != '.' && $item != '..') { + $itemPath = $path.'/'.$item; + $this->setPermissionfiles($itemPath); + } + } + } + } + } + + + /** + * Unzip folder or only file. + * + * @param string $zipFile File to unzip. + * @param string $target_path Target path into unzip. + * @param string $file If only need unzip one file. + * + * @return boolean $result True if the file has been successfully decompressed. + */ + public function unZip($zipFile, $target_path, $file=null) + { + $zip = new \ZipArchive; + + if ($zip->open($zipFile) === true) { + $zip->extractTo($target_path, $file); + $zip->close(); + return true; + } else { + return false; + } + } + + +} diff --git a/pandora_console/images/report-task.svg b/pandora_console/images/report-task.svg new file mode 100644 index 0000000000..b16b7144da --- /dev/null +++ b/pandora_console/images/report-task.svg @@ -0,0 +1,8 @@ + + + Reportes programados@svg + + + + + \ No newline at end of file diff --git a/pandora_console/images/widgets/netflow.png b/pandora_console/images/widgets/netflow.png new file mode 100644 index 0000000000..5a34c1635f Binary files /dev/null and b/pandora_console/images/widgets/netflow.png differ diff --git a/pandora_console/images/wizard/Configurar_app@svg.svg b/pandora_console/images/wizard/Configurar_app@svg.svg new file mode 100644 index 0000000000..59507e2cf4 --- /dev/null +++ b/pandora_console/images/wizard/Configurar_app@svg.svg @@ -0,0 +1,22 @@ + + + + Configurar app@svg + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pandora_console/images/wizard/Custom_apps@svg.svg b/pandora_console/images/wizard/Custom_apps@svg.svg new file mode 100644 index 0000000000..23e251912d --- /dev/null +++ b/pandora_console/images/wizard/Custom_apps@svg.svg @@ -0,0 +1,21 @@ + + + + Custom apps@svg + Created with Sketch. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pandora_console/images/wizard/app_generico.svg b/pandora_console/images/wizard/app_generico.svg new file mode 100644 index 0000000000..99d3e5cf42 --- /dev/null +++ b/pandora_console/images/wizard/app_generico.svg @@ -0,0 +1,18 @@ + + + + App genérico@svg + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/pandora_console/images/wizard/applications.png b/pandora_console/images/wizard/applications.png new file mode 100644 index 0000000000..01c10178bd Binary files /dev/null and b/pandora_console/images/wizard/applications.png differ diff --git a/pandora_console/images/wizard/cloud.png b/pandora_console/images/wizard/cloud.png new file mode 100644 index 0000000000..a016599e2f Binary files /dev/null and b/pandora_console/images/wizard/cloud.png differ diff --git a/pandora_console/images/wizard/consoletasks.png b/pandora_console/images/wizard/consoletasks.png new file mode 100644 index 0000000000..0087897495 Binary files /dev/null and b/pandora_console/images/wizard/consoletasks.png differ diff --git a/pandora_console/include/ajax/audit_log.php b/pandora_console/include/ajax/audit_log.php index c979568b21..026d8ca881 100644 --- a/pandora_console/include/ajax/audit_log.php +++ b/pandora_console/include/ajax/audit_log.php @@ -84,7 +84,7 @@ if ($save_log_filter) { if ($recover_aduit_log_select) { - echo json_encode(audit_get_audit_filter_select()); + echo json_encode(audit_get_audit_filter_select_fix_order()); } if ($update_log_filter) { @@ -190,7 +190,7 @@ function show_filter() { draggable: true, modal: false, closeOnEscape: true, - width: 380 + width: "auto" }); } @@ -207,12 +207,13 @@ function load_filter_values() { }, success: function(data) { var options = ""; + console.log(data); $.each(data,function(i,value){ if (i == 'text'){ $("#text-filter_text").val(value); } if (i == 'period'){ - $("#text-filter_period").val(value); + $("#filter_period").val(value).change(); } if (i == 'ip'){ $("#text-filter_ip").val(value); @@ -395,7 +396,7 @@ function save_new_filter() { "save_log_filter" : 1, "id_name" : $("#text-id_name").val(), "text" : $("#text-filter_text").val(), - "period" : $("#text-filter_period").val(), + "period" : $("#filter_period :selected").val(), "ip" : $('#text-filter_ip').val(), "type" : $('#filter_type :selected').val(), "user" : $('#filter_user :selected').val(), @@ -431,7 +432,7 @@ function save_update_filter() { "update_log_filter" : 1, "id" : $("#overwrite_filter :selected").val(), "text" : $("#text-filter_text").val(), - "period" : $("#text-filter_period").val(), + "period" : $("#filter_period :selected").val(), "ip" : $('#text-filter_ip').val(), "type" : $('#filter_type :selected').val(), "user" : $('#filter_user :selected').val(), diff --git a/pandora_console/include/ajax/manage_extensions.ajax.php b/pandora_console/include/ajax/manage_extensions.ajax.php new file mode 100644 index 0000000000..b116277a23 --- /dev/null +++ b/pandora_console/include/ajax/manage_extensions.ajax.php @@ -0,0 +1,60 @@ +ajaxMethod($method) === true) { + $actions->{$method}(); + } else { + $actions->errorAjax('Unavailable method.'); + } +} else { + $actions->errorAjax('Method not found. ['.$method.']'); +} + + +// Stop any execution. +exit; diff --git a/pandora_console/include/class/AuditLog.class.php b/pandora_console/include/class/AuditLog.class.php index 98bca38e43..f35f4e4e6d 100644 --- a/pandora_console/include/class/AuditLog.class.php +++ b/pandora_console/include/class/AuditLog.class.php @@ -178,7 +178,7 @@ class AuditLog extends HTML [ 'id' => $this->tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, @@ -469,7 +469,7 @@ class AuditLog extends HTML success: function(data) { var options = ""; $.each(data,function(key,value){ - options += ""; + options += ""; }); $('#overwrite_filter').html(options); $('#overwrite_filter').select2(); @@ -509,8 +509,12 @@ class AuditLog extends HTML /* Filter management */ $('#button-load-filter').click(function (){ if($('#load-filter-select').length) { - $('#load-filter-select').dialog({width: "20%", - maxWidth: "25%", + $('#load-filter-select').dialog({ + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + width: "auto", title: "" }); $.ajax({ @@ -523,8 +527,9 @@ class AuditLog extends HTML }, success: function(data) { var options = ""; + console.log(data) $.each(data,function(key,value){ - options += ""; + options += ""; }); $('#filter_id').html(options); $('#filter_id').select2(); diff --git a/pandora_console/include/class/CalendarManager.class.php b/pandora_console/include/class/CalendarManager.class.php index ba1761d6f9..311559c4e2 100644 --- a/pandora_console/include/class/CalendarManager.class.php +++ b/pandora_console/include/class/CalendarManager.class.php @@ -1040,7 +1040,7 @@ class CalendarManager 'id' => 'templates_alerts_special_days', 'return' => true, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'godmode/alerts/alert_special_days', diff --git a/pandora_console/include/class/ConfigPEN.class.php b/pandora_console/include/class/ConfigPEN.class.php index 2177e73a74..cea6123f08 100644 --- a/pandora_console/include/class/ConfigPEN.class.php +++ b/pandora_console/include/class/ConfigPEN.class.php @@ -612,7 +612,7 @@ class ConfigPEN extends HTML 'id' => $tableId, 'return' => true, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, diff --git a/pandora_console/include/class/ConsoleSupervisor.php b/pandora_console/include/class/ConsoleSupervisor.php index 9142f9a692..12ed8e56be 100644 --- a/pandora_console/include/class/ConsoleSupervisor.php +++ b/pandora_console/include/class/ConsoleSupervisor.php @@ -595,7 +595,6 @@ class ConsoleSupervisor 'days_delete_unknown' => 'Max. days before unknown modules are deleted', 'days_delete_not_initialized' => 'Max. days before delete not initialized modules', 'days_autodisable_deletion' => 'Max. days before autodisabled agents are deleted', - 'delete_old_network_matrix' => 'Max. days before delete old network matrix data', 'report_limit' => 'Item limit for real-time reports', 'event_view_hr' => 'Default hours for event view', 'big_operation_step_datos_purge' => 'Big Operation Step to purge old data', diff --git a/pandora_console/include/class/CredentialStore.class.php b/pandora_console/include/class/CredentialStore.class.php index b82a129cd1..937f505f8d 100644 --- a/pandora_console/include/class/CredentialStore.class.php +++ b/pandora_console/include/class/CredentialStore.class.php @@ -827,7 +827,7 @@ class CredentialStore extends Wizard [ 'id' => $this->tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, diff --git a/pandora_console/include/class/Diagnostics.class.php b/pandora_console/include/class/Diagnostics.class.php index 7483cbca30..2c00a6b328 100644 --- a/pandora_console/include/class/Diagnostics.class.php +++ b/pandora_console/include/class/Diagnostics.class.php @@ -1579,7 +1579,7 @@ class Diagnostics extends Wizard [ 'id' => $tableId, 'class' => 'info_table caption_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columnNames, 'ajax_data' => [ @@ -1591,6 +1591,7 @@ class Diagnostics extends Wizard 'no_sortable_columns' => [-1], 'caption' => $title, 'print' => true, + 'mini_csv' => true, ] ); } else { diff --git a/pandora_console/include/class/EventSound.class.php b/pandora_console/include/class/EventSound.class.php index e485ac4dfb..5658b44324 100644 --- a/pandora_console/include/class/EventSound.class.php +++ b/pandora_console/include/class/EventSound.class.php @@ -320,7 +320,7 @@ class EventSound extends HTML [ 'id' => $this->tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, diff --git a/pandora_console/include/class/ExtensionsDiscovery.class.php b/pandora_console/include/class/ExtensionsDiscovery.class.php new file mode 100644 index 0000000000..da26fb1780 --- /dev/null +++ b/pandora_console/include/class/ExtensionsDiscovery.class.php @@ -0,0 +1,2555 @@ +section = $_section; + $this->mode = $_mode; + $this->url = 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz='.$_section; + $this->loadConfig(); + } + + + /** + * Load config from extension. + * + * @return void + */ + private function loadConfig() + { + $row = db_get_row('tdiscovery_apps', 'short_name', $this->mode); + $this->id = $row['id_app']; + $this->name = $row['name']; + $this->description = $row['description']; + } + + + /** + * Return array extensions filtered by section + * + * @return array Extensions for + */ + public function loadExtensions() + { + global $config; + // Check access. + check_login(); + $extensions = []; + $rows = $this->getExtensionsApps(); + foreach ($rows as $key => $extension) { + $logo = $this->path.'/'.$extension['short_name'].'/'.$this->icon; + if (file_exists($config['homedir'].$logo) === false) { + $logo = $this->defaultLogo; + } + + $extensions[] = [ + 'icon' => $logo, + 'label' => $extension['name'], + 'url' => ui_get_full_url( + 'index.php?sec=gservers&sec2=godmode/servers/discovery&wiz='.$this->section.'&mode='.$extension['short_name'] + ), + ]; + } + + return $extensions; + } + + + /** + * Return all extensions from apps section + * + * @return array extensions. + */ + public function getExtensionsApps() + { + return db_get_all_rows_filter('tdiscovery_apps', ['section' => $this->section]); + + } + + + /** + * Load the extension information from discovery_definition.ini. + * + * @return array Information ini file. + */ + public function loadIni() + { + global $config; + $iniFile = parse_ini_file($config['homedir'].$this->path.'/'.$this->mode.'/discovery_definition.ini', true, INI_SCANNER_TYPED); + + return $iniFile; + } + + + /** + * Return next page from config_steps. + * + * @return integer Return the number of next page. + */ + public function nextPage() + { + $pages = array_keys($this->iniFile['config_steps']['name']); + if ($this->currentPage === 0 || empty($this->currentPage) === true) { + return $pages[0]; + } + + foreach ($pages as $k => $page) { + if ($page === $this->currentPage) { + if (end($pages) === $this->currentPage) { + return $this->currentPage; + } else { + return $pages[($k + 1)]; + } + } + } + } + + + /** + * Draw the extension forms. + * + * @return boolean Return boolean if exist error. + */ + public function run() + { + ui_require_javascript_file('extensions_discovery'); + $_iniFile = $this->loadIni(); + if ($_iniFile === false) { + include 'general/noaccess.php'; + return false; + } + + $this->iniFile = $_iniFile; + if (empty($this->iniFile['config_steps']) === false) { + $this->lastPage = end(array_keys($this->iniFile['config_steps']['name'])); + } else { + $this->lastPage = 0; + } + + $this->currentPage = (int) get_parameter('page', '0'); + $this->idTask = get_parameter('id_task', ''); + $action = get_parameter('action', ''); + $isTheEnd = get_parameter('complete_button', ''); + + // Control parameters and errors. + $error = false; + + if ($action === 'task_definition_form') { + $error = $this->processTaskDefinition(); + } + + if ($action === 'process_macro') { + $error = $this->processCustomMacro(); + } + + $task = $this->getTask(); + + if ($task === false && $this->currentPage > 0) { + $error = __('Task not defined'); + } + + // Build breadcrum. + $breadcrum = [ + [ + 'link' => 'index.php?sec=gservers&sec2=godmode/servers/discovery', + 'label' => 'Discovery', + ], + ]; + + switch ($this->section) { + case 'app': + $breadcrum[] = [ + 'link' => $this->url, + 'label' => __('Application'), + ]; + break; + + case 'cloud': + $breadcrum[] = [ + 'link' => $this->url, + 'label' => __('Cloud'), + ]; + break; + + case 'custom': + $breadcrum[] = [ + 'link' => $this->url, + 'label' => __('Custom'), + ]; + break; + + default: + $breadcrum[] = [ + 'link' => $this->url, + 'label' => __('Custom'), + ]; + break; + } + + $parameters = ''; + if (empty($this->idTask) === false) { + $parameters .= '&id_task='.$this->idTask; + } + + $breadcrum[] = [ + 'link' => $this->url.'&mode='.$this->mode.$parameters, + 'label' => 'Task definition', + 'selected' => ((0 === (int) $this->currentPage) ? 1 : 0), + ]; + + foreach ($this->iniFile['config_steps']['name'] as $key => $step) { + $parameters = '&mode='.$this->mode.'&page='.$key; + if (empty($this->idTask) === false) { + $parameters .= '&id_task='.$this->idTask; + } + + $breadcrum[] = [ + 'link' => $this->url.$parameters, + 'label' => $step, + 'selected' => (($key === (int) $this->currentPage) ? 1 : 0), + ]; + } + + // Avoid to print header out of wizard. + $this->prepareBreadcrum($breadcrum); + + // Header. + ui_print_page_header( + $this->iniFile['discovery_extension_definition']['name'], + '', + false, + '', + true, + '', + false, + '', + GENERIC_SIZE_TEXT, + '', + $this->printHeader(true) + ); + + if ($error !== false) { + ui_print_error_message( + $error + ); + return; + } else if ($action !== '') { + ui_print_success_message(__('Operation realized')); + + if (empty($isTheEnd) === false) { + header('Location:'.$config['homeurl'].'index.php?sec=discovery&sec2=godmode/servers/discovery&wiz=tasklist'); + } + } + + $_url = ui_get_full_url( + sprintf( + $this->url.'&mode=%s&page=%s%s', + $this->mode, + $this->nextPage(), + (empty($this->idTask) === false) ? '&id_task='.$this->idTask : '', + ) + ); + + $table = new StdClass(); + $table->id = 'form_editor'; + $table->width = '100%'; + $table->class = 'databox filter-table-adv max_floating_element_size'; + + $table->style = []; + $table->style[0] = 'width: 50%'; + $table->style[1] = 'width: 50%'; + $table->data = []; + if ($this->currentPage === 0) { + // If page is 0 then create form for task definition. + $table->data = $this->viewTaskDefinition(); + } else { + // If page is bigger than 0 then render form .ini. + $table->data = $this->viewMacroForm(); + } + + echo '
'; + html_print_table($table); + + $actionButtons = ''; + + if ($this->currentPage !== $this->nextPage()) { + $actionButtons = html_print_submit_button( + __('Next'), + 'next_button', + false, + [ + 'class' => 'sub', + 'icon' => 'plus', + ], + true + ); + } + + $actionButtons .= html_print_submit_button( + __('Complete setup'), + 'complete_button', + false, + [ + 'class' => 'sub', + 'icon' => 'update', + 'value' => '1', + ], + true + ); + + html_print_action_buttons($actionButtons); + echo '
'; + + } + + + /** + * Draw a select with the pandora data + * + * @param string $selectData Type of select. + * @param string $name Name of select. + * @param string $defaultValue Default value. + * @param boolean $multiple Define if the select is multiple. + * @param boolean $required Define if field is required. + * + * @return string Return the html select. + */ + private function drawSelectPandora($selectData, $name, $defaultValue, $multiple=false, $required=false) + { + if ($multiple === true && $selectData !== 'interval') { + $name .= '[]'; + $defaultValue = json_decode($defaultValue); + } else { + $defaultValue = io_safe_input($defaultValue); + } + + switch ($selectData) { + case 'agent_groups': + $input = html_print_select_groups( + false, + 'AR', + true, + $name, + $defaultValue, + '', + '', + '', + true, + $multiple, + false, + '', + false, + false, + false, + false, + 'id_grupo', + true, + false, + false, + false, + false, + $required + ); + break; + + case 'agents': + $input = html_print_select_from_sql( + 'SELECT nombre, alias as n FROM tagente', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%;', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'module_groups': + $input = html_print_select_from_sql( + 'SELECT id_mg, name + FROM tmodule_group ORDER BY name', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'modules': + $input = html_print_select_from_sql( + 'select nombre, nombre as n from tagente_modulo', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'module_types': + $input = html_print_select_from_sql( + 'select nombre, descripcion from ttipo_modulo', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'status': + $module_status_arr = []; + // Default. + $module_status_arr[AGENT_MODULE_STATUS_NORMAL] = __('Normal'); + $module_status_arr[AGENT_MODULE_STATUS_WARNING] = __('Warning'); + $module_status_arr[AGENT_MODULE_STATUS_CRITICAL_BAD] = __('Critical'); + $module_status_arr[AGENT_MODULE_STATUS_UNKNOWN] = __('Unknown'); + $module_status_arr[AGENT_MODULE_STATUS_NOT_INIT] = __('Not init'); + $input = html_print_select( + $module_status_arr, + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + '', + false, + 'width:100%', + false, + false, + false, + '', + false, + false, + $required, + false, + true, + true + ); + break; + + case 'alert_templates': + $input = html_print_select_from_sql( + 'select id, name from talert_templates', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'alert_actions': + $input = html_print_select_from_sql( + 'select id, name from talert_actions', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'interval': + $input = html_print_extended_select_for_time( + $name, + (string) $defaultValue, + '', + '', + '0', + false, + true + ); + break; + + case 'tags': + $input = html_print_select_from_sql( + 'select id_tag, name from ttag', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.custom': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "custom"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.aws': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "AWS"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.azure': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "AZURE"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.sap': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "SAP"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.snmp': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "SNMP"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.gcp': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "GOOGLE"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'credentials.wmi': + $input = html_print_select_from_sql( + 'select identifier, identifier as i from tcredential_store WHERE product = "WMI"', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + case 'os': + $input = html_print_select_from_sql( + 'SELECT id_os, name FROM tconfig_os ORDER BY name', + $name, + $defaultValue, + '', + ($multiple === false) ? __('None selected') : '', + '', + true, + $multiple, + true, + false, + 'width: 100%', + false, + GENERIC_SIZE_TEXT, + '', + $required + ); + break; + + default: + $input = html_print_select( + [], + $name, + $defaultValue, + '', + '', + 0, + true + ); + break; + } + + return $input; + } + + + /** + * Draw input from parameters of .ini. + * + * @param array $parameters Configuration of input. + * @param boolean $implicit Indicates if all the configuration is indicated in the array. + * + * @return string Html from input. + */ + public function drawInput($parameters, $implicit=false) + { + $input = ''; + $defaultValue = $this->macrosValues[$parameters['macro']]; + switch ($parameters['type']) { + case 'string': + $input = html_print_input_text( + $parameters['macro'], + $defaultValue, + '', + 50, + 255, + true, + false, + ($parameters['mandatory_field'] === false) ? false : true + ); + break; + + case 'number': + $config = [ + 'type' => 'number', + 'name' => $parameters['macro'], + 'value' => $defaultValue, + 'return' => true, + ]; + if ($parameters['mandatory_field'] !== false) { + $config['required'] = true; + } + + $input = html_print_input($config); + break; + + case 'password': + $isEncrypted = (bool) $this->macrosValues[$parameters['encrypt_on_true']]; + if ($isEncrypted === true) { + $defaultValueEncrypted = $this->encryptPassword($defaultValue, true); + if (empty($defaultValueEncrypted) === false) { + $defaultValue = $defaultValueEncrypted; + } + } + + $input = html_print_input_password( + $parameters['macro'], + $defaultValue, + '', + 50, + 255, + true, + false, + ($parameters['mandatory_field'] === false) ? false : true, + '', + 'on' + ); + if (empty($parameters['encrypt_on_true']) === false) { + $input .= html_print_input_hidden( + $parameters['macro'].'_encrypt', + $parameters['encrypt_on_true'], + true + ); + } + break; + + case 'checkbox': + $input = html_print_checkbox_switch( + $parameters['macro'], + 1, + (bool) $defaultValue, + true + ); + break; + + case 'textarea': + $input = html_print_textarea( + $parameters['macro'], + 5, + 20, + $defaultValue, + ($parameters['mandatory_field'] === false) ? '' : 'required="required"', + true + ); + break; + + case 'select': + if (in_array($parameters['select_data'], $this->pandoraSelectData) === true) { + $input = $this->drawSelectPandora( + $parameters['select_data'], + $parameters['macro'], + $defaultValue, + false, + ($parameters['mandatory_field'] === false) ? false : true, + ); + $parameters['type'] = $parameters['select_data']; + } else { + if ($implicit === false) { + $options = $this->iniFile[$parameters['select_data']]['option']; + } else { + $options = $parameters['select_data']; + } + + $input = html_print_select( + $options, + $parameters['macro'], + $defaultValue, + '', + __('None selected'), + '', + true, + false, + true, + '', + false, + 'width: 100%;', + false, + false, + false, + '', + false, + false, + ($parameters['mandatory_field'] === false) ? false : true, + ); + } + break; + + case 'multiselect': + if (in_array($parameters['select_data'], $this->pandoraSelectData) === true) { + $input = $this->drawSelectPandora( + $parameters['select_data'], + $parameters['macro'], + $defaultValue, + true, + ); + $parameters['type'] = $parameters['select_data']; + } else { + if ($implicit === false) { + $options = $this->iniFile[$parameters['select_data']]['option']; + } else { + $options = $parameters['select_data']; + } + + $input = html_print_select( + $options, + $parameters['macro'].'[]', + json_decode($defaultValue, true), + '', + '', + 0, + true, + true, + true, + '', + false, + 'width: 100%', + false, + false, + false, + '', + false, + false, + false, + false, + true, + true + ); + } + break; + + case 'tree': + // Show bucket tree explorer. + ui_require_javascript_file('pandora_snmp_browser'); + if ($implicit === false) { + $treeData = $this->iniFile[$parameters['tree_data']]; + $treeInfo = $this->getTreeStructure($parameters, $treeData); + } else { + $treeData = $parameters['tree_data']; + $treeInfo = $this->getTreeStructureByScript($parameters, $treeData); + } + + $input = ui_print_tree( + $treeInfo, + // Id. + 0, + // Depth. + 0, + // Last. + 0, + // Last_array. + [], + // Sufix. + true, + // Return. + true, + // Descriptive ids. + false + ); + break; + + default: + $input = html_print_input_text( + $parameters['macro'], + $defaultValue, + '', + 50, + 255, + true, + false, + ($parameters['mandatory_field'] === false) ? false : true + ); + break; + } + + $input .= html_print_input_hidden( + $parameters['macro'].'type', + $parameters['type'], + true + ); + $class = ''; + if ($parameters['show_on_true'] !== null) { + $class = $parameters['macro'].'_hide'; + $input .= $this->showOnTrue($parameters['show_on_true'], $class); + } + + $name = $parameters['name']; + if (empty($parameters['tip']) === false) { + $name .= ui_print_help_tip($parameters['tip'], true); + } + + return html_print_label_input_block( + $name, + $input, + ['div_class' => $class] + ); + } + + + /** + * Return the task app from database. + * + * @return array $task Task of database. + */ + private function getTask() + { + return db_get_row_filter( + 'trecon_task', + [ + 'id_app' => $this->id, + 'id_rt' => $this->idTask, + 'type' => 15, + ], + ); + } + + + /** + * Returns the value of the macro. + * + * @param string $macro Name of macro for filter. + * + * @return mixed Value of the macro. + */ + private function getValueMacro($macro) + { + return db_get_value_filter( + 'value', + 'tdiscovery_apps_tasks_macros', + [ + 'id_task' => $this->idTask, + 'macro' => $macro, + ] + ); + } + + + /** + * Return form for macro form. + * + * @return array $form Form macro. + */ + private function viewMacroForm() + { + $data = []; + + $macros = db_get_all_rows_filter( + 'tdiscovery_apps_tasks_macros', + ['id_task' => $this->idTask], + ['*'] + ); + if ($macros !== false) { + foreach ($macros as $key => $macro) { + $this->macrosValues[$macro['macro']] = io_safe_output($macro['value']); + } + } + + // Process ini or script. + $customFields = $this->iniFile['config_steps']['custom_fields'][$this->currentPage]; + $customFieldsByScript = $this->getStructureFormByScript($this->iniFile['config_steps']['script_data_fields'][$this->currentPage]); + + if ($customFields === null && $customFieldsByScript === null) { + $data[0][0] = html_print_image( + 'images/no_data_toshow.png', + true, + ['class' => 'w200px'] + ); + $data[1][0] = html_print_input_hidden( + 'action', + 'process_macro', + true + ); + return $data; + } + + $columns = 2; + if ($this->iniFile['config_steps']['fields_columns'][$this->currentPage] !== null + && $this->iniFile['config_steps']['fields_columns'][$this->currentPage] === 1 + ) { + $columns = 1; + } + + $row = 0; + $col = 0; + foreach ($customFieldsByScript as $key => $value) { + $this->nameFields[] = $value['macro']; + $data[$row][$col] = $this->drawInput($value, true); + $col++; + if ($col == $columns) { + $row++; + $col = 0; + } + } + + foreach ($this->iniFile[$customFields]['macro'] as $key => $id) { + $parameters = [ + 'macro' => $id, + 'name' => $this->iniFile[$customFields]['name'][$key], + 'tip' => $this->iniFile[$customFields]['tip'][$key], + 'type' => $this->iniFile[$customFields]['type'][$key], + 'placeholder' => $this->iniFile[$customFields]['placeholder'][$key], + 'mandatory_field' => $this->iniFile[$customFields]['mandatory_field'][$key], + 'show_on_true' => $this->iniFile[$customFields]['show_on_true'][$key], + 'encrypt_on_true' => $this->iniFile[$customFields]['encrypt_on_true'][$key], + 'select_data' => $this->iniFile[$customFields]['select_data'][$key], + 'tree_data' => $this->iniFile[$customFields]['tree_data'][$key], + ]; + $this->nameFields[] = $id; + $data[$row][$col] = $this->drawInput($parameters); + $col++; + if ($col == $columns) { + $row++; + $col = 0; + } + } + + $data[($row + 1)][1] = html_print_input_hidden( + 'action', + 'process_macro', + true + ); + $data[($row + 1)][1] .= html_print_input_hidden( + 'name_fields', + implode(',', $this->nameFields), + true + ); + + return $data; + } + + + /** + * Return form for task definition. + * + * @return array $form Form for task definition. + */ + private function viewTaskDefinition() + { + $task = $this->getTask(); + + $data = []; + $data[0][0] = html_print_label_input_block( + __('Task name'), + html_print_input_text( + 'task_name', + $task['name'], + '', + 50, + 255, + true, + false, + true + ) + ); + + $data[1][0] = html_print_label_input_block( + __('Description'), + html_print_textarea( + 'description', + 5, + 20, + $task['description'], + '', + true + ) + ); + + $data[2][0] = html_print_label_input_block( + __('Discovery server'), + html_print_select_from_sql( + sprintf( + 'SELECT id_server, name + FROM tserver + WHERE server_type = %d + ORDER BY name', + SERVER_TYPE_DISCOVERY + ), + 'discovery_server', + $task['id_recon_server'], + '', + '', + '0', + true, + false, + true, + false, + false, + false, + GENERIC_SIZE_TEXT, + '', + false + ) + ); + + $data[3][0] = html_print_label_input_block( + __('Group'), + html_print_select_groups( + false, + 'AR', + false, + 'group', + $task['id_group'], + '', + '', + 0, + true, + false, + false, + '', + false, + false, + false, + false, + 'id_grupo', + false, + false, + false, + false, + false, + true + ) + ); + + $inputs_interval = html_print_select( + [ + 'defined' => 'Defined', + 'manual' => 'Manual', + ], + 'mode_interval', + ($task['interval_sweep'] === '0') ? 'manual' : 'defined', + 'changeModeInterval(this)', + '', + '0', + true, + false, + true, + '', + false + ).html_print_extended_select_for_time( + 'interval', + (empty($task['interval_sweep']) === true) ? '300' : $task['interval_sweep'], + '', + '', + '0', + false, + true, + false, + true, + ); + $js_variables = ''; + $data[4][0] = html_print_label_input_block( + __('Interval'), + html_print_div( + [ + 'style' => 'display: flex;max-width: 345px; justify-content: space-between;', + 'content' => $inputs_interval.$js_variables, + ], + true + ) + ); + + $data[5][0] = html_print_label_input_block( + __('Timeout').ui_print_help_tip('This timeout will be applied for each task execution', true), + html_print_extended_select_for_time( + 'tiemout', + (empty($task['executions_timeout']) === true) ? '60' : $task['executions_timeout'], + '', + '', + '0', + false, + true + ), + ); + + $data[6][0] = html_print_input_hidden( + 'action', + 'task_definition_form', + true + ); + + $data[7][0] = html_print_input_hidden( + 'id_task', + $task['id_rt'], + true + ); + + return $data; + } + + + /** + * Sabe data from task definition form. + * + * @return string $error Error string if exist. + */ + private function processTaskDefinition() + { + $taskName = get_parameter('task_name', ''); + $description = get_parameter('description', ''); + $discoveryServer = get_parameter('discovery_server', ''); + $group = get_parameter('group', 0); + $mode_interval = get_parameter('mode_interval', 'defined'); + $interval = get_parameter('interval', ''); + $tiemout = get_parameter('tiemout', 60); + $completeTask = get_parameter('complete_button', ''); + + if ($mode_interval === 'manual') { + $interval = '0'; + } + + $error = false; + + if ($taskName === '' + || $discoveryServer === '' + || $group === '' + || $interval === '' + ) { + $error = __('Fields empties'); + return $error; + } + + if ($this->idTask === '') { + db_process_sql_begin(); + try { + $_idTask = db_process_sql_insert( + 'trecon_task', + [ + 'id_app' => $this->id, + 'name' => $taskName, + 'description' => $description, + 'id_group' => $group, + 'interval_sweep' => $interval, + 'id_recon_server' => $discoveryServer, + 'type' => 15, + 'setup_complete' => (empty($completeTask) === false) ? 1 : 0, + 'executions_timeout' => $tiemout, + ] + ); + + if ($_idTask === false) { + $error = __('Error creating the discovery task'); + } else { + $this->idTask = $_idTask; + $this->autoLoadConfigMacro(); + } + } catch (Exception $e) { + $error = __('Error creating the discovery task'); + } + + if ($error === false) { + db_process_sql_commit(); + } else { + db_process_sql_rollback(); + } + } else { + $result = db_process_sql_update( + 'trecon_task', + [ + 'id_app' => $this->id, + 'name' => $taskName, + 'description' => $description, + 'id_group' => $group, + 'interval_sweep' => $interval, + 'id_recon_server' => $discoveryServer, + 'type' => 15, + 'setup_complete' => (empty($completeTask) === false) ? 1 : 0, + 'executions_timeout' => $tiemout, + ], + ['id_rt' => $this->idTask] + ); + + if ($result === false) { + $error = __('Error updating the discovery task'); + } + } + + return $error; + } + + + /** + * Process the values of input from macro defined in .ini + * + * @return string $error Error string if exist. + */ + private function processCustomMacro() + { + $error = false; + + $keyParameters = explode(',', get_parameter('name_fields', '')); + + foreach ($keyParameters as $v => $key) { + $type = get_parameter($key.'type', ''); + switch ($type) { + case 'checkbox': + $value = get_parameter_switch($key, 0); + break; + + case 'multiselect': + $value = io_safe_input(json_encode(get_parameter($key, ''))); + break; + + case 'password': + $value = get_parameter($key, ''); + $encryptKey = get_parameter($key.'_encrypt', ''); + if ($encryptKey !== '') { + $encrypt = (bool) get_parameter_switch($encryptKey, 0); + if ($encrypt === true) { + $valueEncrypt = $this->encryptPassword($value); + if (empty($valueEncrypt) === false) { + $value = $valueEncrypt; + } + } + } + break; + + default: + $value = get_parameter($key, ''); + break; + } + + if (is_array($value) === true) { + $value = io_safe_input(json_encode($value)); + } + + $exist = db_get_row_filter( + 'tdiscovery_apps_tasks_macros', + [ + 'id_task' => $this->idTask, + 'macro' => $key, + ] + ); + + if (in_array($type, $this->pandoraSelectData) === false) { + $type = 'custom'; + } + + if ($exist === false) { + $result = db_process_sql_insert( + 'tdiscovery_apps_tasks_macros', + [ + 'id_task' => $this->idTask, + 'macro' => $key, + 'value' => $value, + 'type' => $type, + ] + ); + if ($result === false) { + $error = __('Field %s not insert', $key); + } + } else { + $result = db_process_sql_update( + 'tdiscovery_apps_tasks_macros', + [ + 'value' => $value, + 'type' => $type, + ], + [ + 'id_task' => $this->idTask, + 'macro' => $key, + ] + ); + if ($result === false) { + $error = __('Field %s not updated', $key); + } + } + } + + $completeTask = get_parameter('complete_button', ''); + if (empty($completeTask) === false) { + $result = db_process_sql_update( + 'trecon_task', + ['setup_complete' => 1], + ['id_rt' => $this->idTask] + ); + if ($result === false) { + $error = __('Task not updated'); + } + } + + return $error; + } + + + /** + * Check if name of input macro is correct. + * + * @param string $name Name of input. + * + * @return boolean value true if name is correct. + */ + private function isCorrectNameInput($name) + { + if (substr($name, 0, 1) === '_' && substr($name, -1) === '_') { + return true; + } else { + return false; + } + } + + + /** + * Return logic for component show on true. + * + * @param string $checkbox Name the checkbox for hide input. + * @param string $elementToHide Name the element to hide HIS PARENT. + * + * @return string String Name the element + */ + private function showOnTrue($checkbox, $elementToHide) + { + return ''; + } + + + /** + * Load the macros task in database + * + * @throws Exception Excepcion to control possible error for default value. + * + * @return void + */ + private function autoLoadConfigMacro() + { + $defaultValues = $this->iniFile['discovery_extension_definition']['default_value']; + + foreach ($defaultValues as $key => $value) { + if ($value === false) { + $value = 0; + } + + $result = db_process_sql_insert( + 'tdiscovery_apps_tasks_macros', + [ + 'id_task' => $this->idTask, + 'macro' => $key, + 'value' => (string) io_safe_input($value), + 'type' => 'custom', + ] + ); + if ($result === false) { + throw new Exception('Error creating task'); + } + } + + $tempFiles = $this->iniFile['tempfile_confs']['file']; + + foreach ($tempFiles as $key => $value) { + $result = db_process_sql_insert( + 'tdiscovery_apps_tasks_macros', + [ + 'id_task' => $this->idTask, + 'macro' => $key, + 'value' => (string) io_safe_input($value), + 'type' => 'custom', + 'temp_conf' => 1, + ] + ); + if ($result === false) { + throw new Exception('Error creating task'); + } + } + } + + + /** + * Return array structure for draw tree when array is by .ini. + * + * @param array $parent Parent from the tree. + * @param array $firstChildren First children from parent. + * + * @return array $treeInfo Return the array with format for render treee + */ + private function getTreeStructure($parent, $firstChildren) + { + $treeInfo = []; + foreach ($firstChildren['name'] as $key => $value) { + $checked = false; + $name = (empty($firstChildren['macro'][$key]) === false) ? $firstChildren['macro'][$key].'[]' : $parent['id'].'[]'; + $nameField = (empty($firstChildren['macro'][$key]) === false) ? $firstChildren['macro'][$key] : $parent['id']; + if (in_array($nameField, $this->nameFields) === false) { + $this->nameFields[] = $nameField; + } + + $checkedValues = json_decode(io_safe_output($this->macrosValues[$nameField]), true); + if (empty($checkedValues) === false) { + if (in_array($firstChildren['value'][$key], $checkedValues)) { + $checked = true; + } + } + + $treeInfo['__LEAVES__'][$key] = [ + 'label' => $value, + 'selectable' => (bool) $firstChildren['selectable'][$key], + 'name' => $name, + 'value' => $firstChildren['value'][$key], + 'checked' => $checked, + ]; + + if (empty($firstChildren['children'][$key]) === false) { + $children = $this->iniFile[$firstChildren['children'][$key]]; + $treeInfo['__LEAVES__'][$key]['sublevel'] = $this->getTreeStructure($parent, $children); + } + } + + return $treeInfo; + } + + + /** + * Return array structure for draw tree when array is by script. + * + * @param array $parent Parent from the tree. + * @param array $firstChildren First children from parent. + * + * @return array $treeInfo Return the array with format for render treee + */ + private function getTreeStructureByScript($parent, $firstChildren) + { + $treeInfo = []; + foreach ($firstChildren as $key => $value) { + $checked = false; + $name = (empty($value['macro']) === false) ? $value['macro'].'[]' : $parent['macro'].'[]'; + $nameField = (empty($value['macro']) === false) ? $value['macro'] : $parent['macro']; + if (in_array($nameField, $this->nameFields) === false) { + $this->nameFields[] = $nameField; + } + + $checkedValues = json_decode(io_safe_output($this->macrosValues[$nameField]), true); + if (empty($checkedValues) === false) { + if (in_array($value['value'], $checkedValues, true) === true) { + $checked = true; + } + } + + $treeInfo['__LEAVES__'][$key] = [ + 'label' => $value['name'], + 'selectable' => (bool) $value['selectable'], + 'name' => $name, + 'value' => $value['value'], + 'checked' => $checked, + ]; + + if (empty($value['children']) === false) { + $children = $value['children']; + $treeInfo['__LEAVES__'][$key]['sublevel'] = $this->getTreeStructureByScript($parent, $children); + } + } + + return $treeInfo; + } + + + /** + * Return a json with the form structure for draw. + * + * @param mixed $command String. + * + * @return array Result of command. + */ + private function getStructureFormByScript($command) + { + global $config; + $executionFiles = $this->iniFile['discovery_extension_definition']['execution_file']; + foreach ($executionFiles as $key => $file) { + $file = $config['homedir'].$this->path.'/'.$this->mode.'/'.$file; + $command = str_replace($key, $file, $command); + } + + $values = $this->replaceValues($command); + $command = $values['command']; + $toDelete = $values['delete']; + if (empty($command) === false) { + $result = $this->executeCommand($command); + } + + if (count($toDelete) > 0) { + foreach ($toDelete as $key => $folder) { + Files::rmrf($folder); + } + } + + return json_decode($result, true); + } + + + /** + * Replace values in command + * + * @param string $command String command for replace macros. + * + * @return array $values Command and files to delete. + */ + private function replaceValues($command) + { + preg_match_all('/\b_[a-zA-Z0-9]*_\b/', $command, $matches); + $foldersToDelete = []; + foreach ($matches[0] as $key => $macro) { + $row = db_get_row_filter( + 'tdiscovery_apps_tasks_macros', + [ + 'macro' => $macro, + 'id_task' => $this->idTask, + ] + ); + if ($row !== false) { + if (in_array($row['type'], $this->pandoraSelectData) === true) { + $value = $this->getValuePandoraSelect($row['type'], $row['value']); + $command = str_replace($macro, $value, $command); + } else if ((int) $row['temp_conf'] === 1) { + $nameFile = $row['id_task'].'_'.$row['id_task'].'_'.uniqid(); + $value = $this->getValueTempFile($nameFile, $row['value']); + $command = str_replace($macro, $value, $command); + $foldersToDelete[] = str_replace($nameFile, '', $value); + } else { + $command = str_replace($macro, io_safe_output($row['value']), $command); + } + } + } + + return [ + 'command' => $command, + 'delete' => $foldersToDelete, + ]; + } + + + /** + * Create a temp file for tempfile_confs macros. + * + * @param string $nameFile Name file only. + * @param string $content Content to save to file. + * + * @return string $pathNameFile Name file and with path for replace. + */ + private function getValueTempFile($nameFile, $content) + { + global $config; + $content = io_safe_output($content); + $content = $this->replaceValues($content)['command']; + $nameTempDir = $config['attachment_store'].'/temp_files/'; + if (file_exists($nameTempDir) === false) { + mkdir($nameTempDir); + } + + $tmpPath = Files::tempdirnam( + $nameTempDir, + 'temp_files_' + ); + $pathNameFile = $tmpPath.'/'.$nameFile; + file_put_contents($pathNameFile, $content); + + return $pathNameFile; + } + + + /** + * Return the correct value for pandora select + * + * @param string $type Type of input. + * @param string $id Value of the row macro. + * + * @return string $id New id with the values replaced + */ + private function getValuePandoraSelect($type, $id) + { + $id = io_safe_output($id); + $idsArray = json_decode($id); + if (is_array($idsArray) === false) { + $idsArray = [$id]; + } + + foreach ($idsArray as $key => $v) { + $value = false; + switch ($type) { + case 'agent_groups': + $value = groups_get_name($v); + break; + + case 'module_groups': + $value = modules_get_modulegroup_name($v); + break; + + case 'tags': + $value = tags_get_name($v); + break; + + case 'alert_templates': + $value = alerts_get_alert_template_name($v); + break; + + case 'alert_actions': + $value = alerts_get_alert_action_name($v); + break; + + case 'credentials.custom': + $credentials = CredentialStore::getKey($v); + $value = base64_encode( + json_encode( + [ + 'user' => $credentials['username'], + 'password' => $credentials['password'], + ] + ) + ); + break; + + case 'credentials.aws': + $credentials = CredentialStore::getKey($v); + $value = base64_encode( + json_encode( + [ + 'access_key_id' => $credentials['username'], + 'secret_access_key' => $credentials['password'], + ] + ) + ); + break; + + case 'credentials.azure': + $credentials = CredentialStore::getKey($v); + $value = base64_encode( + json_encode( + [ + 'client_id' => $credentials['username'], + 'application_secret' => $credentials['password'], + 'tenant_domain' => $credentials['extra_1'], + 'subscription_id' => $credentials['extra_2'], + ] + ) + ); + break; + + case 'credentials.gcp': + $credentials = CredentialStore::getKey($v); + $value = base64_encode($credentials['extra_1']); + break; + + case 'credentials.sap': + $credentials = CredentialStore::getKey($v); + $value = base64_encode( + json_encode( + [ + 'user' => $credentials['username'], + 'password' => $credentials['password'], + ] + ) + ); + break; + + case 'credentials.snmp': + $credentials = CredentialStore::getKey($v); + $value = base64_encode($credentials['extra_1']); + break; + + case 'credentials.wmi': + $credentials = CredentialStore::getKey($v); + $value = base64_encode( + json_encode( + [ + 'user' => $credentials['username'], + 'password' => $credentials['password'], + 'namespace' => $credentials['extra_1'], + ] + ) + ); + break; + + case 'os': + $value = get_os_name($v); + break; + + default: + continue; + } + + if ($value !== false) { + $id = str_replace($v, io_safe_output($value), $id); + } + } + + return $id; + } + + + /** + * Encrypt and decode password with the user script. + * + * @param string $password Password to encrypt. + * @param boolean $decode True for decode password. + * + * @return string Password encrypted + */ + private function encryptPassword($password, $decode=false) + { + global $config; + if ($decode === false) { + $command = $this->iniFile['discovery_extension_definition']['passencrypt_exec']; + $nameFile = $this->iniFile['discovery_extension_definition']['passencrypt_script']; + $file = $config['homedir'].$this->path.'/'.$this->mode.'/'.$nameFile; + $command = str_replace('_passencrypt_script_', $file, $command); + } else { + $command = $this->iniFile['discovery_extension_definition']['passdecrypt_exec']; + $nameFile = $this->iniFile['discovery_extension_definition']['passdecrypt_script']; + $file = $config['homedir'].$this->path.'/'.$this->mode.'/'.$nameFile; + $command = str_replace('_passdecrypt_script_', $file, $command); + } + + $command = str_replace('_password_', $password, $command); + + if (empty($command) === false) { + return $this->executeCommand($command); + } else { + return false; + } + } + + + /** + * Valid the .ini + * + * @param array $iniForValidate IniFile to validate. + * + * @return mixed Return false if is ok and string for error. + */ + public static function validateIni($iniForValidate) + { + $discoveryExtension = $iniForValidate['discovery_extension_definition']; + + if (!$discoveryExtension) { + return __('The file does not contain the block \'discovery_extension_definition\''); + } + + if (!array_key_exists('short_name', $discoveryExtension)) { + return __('The \'discovery_extension_definition\' block must contain a \'short_name\' parameter'); + } + + $defaultValues = $discoveryExtension['default_value']; + foreach ($defaultValues as $key => $value) { + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $key)) { + return __( + 'The \'discovery_extension_definition\' block \'default_value\' parameter has a key with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', + $key + ); + } + } + + $shortName = $discoveryExtension['short_name']; + + if (!preg_match('/^[A-Za-z0-9._-]+$/', $shortName)) { + return __('The \'discovery_extension_definition\' block \'short_name\' parameter contains illegal characters. Use only letters (A-Z and a-z), numbers (0-9), points (.), hyphens (-) and underscores (_)'); + } + + if (!array_key_exists('section', $discoveryExtension) || !array_key_exists('name', $discoveryExtension)) { + return __('The \'discovery_extension_definition\' block must contain a \'section\' and a \'name\' parameters'); + } + + $section = $discoveryExtension['section']; + $name = $discoveryExtension['name']; + + if (!in_array($section, ['app', 'cloud', 'custom'])) { + return __('The \'discovery_extension_definition\' block \'section\' parameter must be \'app\', \'cloud\' or \'custom\''); + } + + if (empty($name)) { + return __('The \'discovery_extension_definition\' block \'name\' parameter can not be empty'); + } + + if (!array_key_exists('exec', $discoveryExtension)) { + return __('The \'discovery_extension_definition\' block must contain an \'exec\' parameter'); + } + + $execs = $discoveryExtension['exec']; + + foreach ($execs as $exec) { + if (empty($exec)) { + return __('All the \'discovery_extension_definition\' block \'exec\' parameter definitions can not be empty'); + } + } + + $checkEmptyFields = [ + 'passencrypt_script', + 'passencrypt_exec', + 'passdecrypt_script', + 'passdecrypt_exec', + ]; + + foreach ($checkEmptyFields as $key) { + if ($discoveryExtension[$key] !== null && empty($discoveryExtension[$key]) === true) { + return __('The \'discovery_extension_definition\' block \'%s\' parameter can not be empty', $key); + } + } + + foreach ($discoveryExtension['execution_file'] as $key => $value) { + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $key)) { + return __('The \'discovery_extension_definition\' block \'execution_file\' parameter has a key with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', $key); + } + + if (empty($value) === true) { + return __('All the \'discovery_extension_definition\' block \'execution_file\' parameter definitions can not be empty: \'%s\'', $key); + } + } + + if ($iniForValidate['config_steps'] !== null && empty($iniForValidate['config_steps']) === true) { + return __('The \'config_steps\' block must contain a \'name\' parameter that can not be empty.'); + } + + foreach ($iniForValidate['config_steps'] as $key => $value) { + foreach ($value as $innerKey => $inner_value) { + if (isset($inner_steps[$innerKey])) { + $inner_steps[$innerKey][$key] = $inner_value; + } else { + $inner_steps[$innerKey] = [$key => $inner_value]; + } + } + } + + $customFields = []; + foreach ($inner_steps as $key => $step) { + if (is_numeric($key) === false || $key === 0) { + return __('All the \'config_steps\' block parameters must use numbers greater than 0 as keys: \'%s\'.', $key); + } + + if (empty($step['name']) === true) { + return __('The \'config_steps\' block must contain a \'name\' parameter for all the configuration steps: \'%s\'', $key); + } + + if (empty($step['custom_fields']) === true + && empty($step['script_data_fields']) === true + ) { + return __('The \'config_steps\' block must contain a \'custom_fields\' or \'script_data_fields\' parameter that can not be empty'); + } else if (empty($step['custom_fields']) === false) { + if (empty($iniForValidate[$step['custom_fields']]) === true) { + return __('The \'config_steps\' block \'custom_fields\' parameter has a key value reference that does not exist: \'%s\'', $step['custom_fields']); + } else { + $customFields[] = $step['custom_fields']; + } + } + + $customFields[] = $step['name']; + } + + $requiredKeys = [ + 'macro', + 'name', + 'type', + ]; + + $validTypes = [ + 'string', + 'number', + 'password', + 'textarea', + 'checkbox', + 'select', + 'multiselect', + 'tree', + ]; + + $validSelectData = [ + 'agent_groups', + 'agents', + 'module_groups', + 'modules', + 'module_types', + 'status', + 'alert_templates', + 'alert_actions', + 'interval', + 'tags', + 'credentials.custom', + 'credentials.aws', + 'credentials.azure', + 'credentials.sap', + 'credentials.snmp', + 'credentials.gcp', + 'credentials.wmi', + 'os', + ]; + + $selectDataNames = []; + $treeDataNames = []; + + foreach ($customFields as $key => $customField) { + $innerFields = []; + foreach ($iniForValidate[$customField] as $key => $value) { + foreach ($value as $innerKey => $innerValue) { + if (isset($innerFields[$innerKey])) { + $innerFields[$innerKey][$key] = $innerValue; + } else { + $innerFields[$innerKey] = [$key => $innerValue]; + } + } + } + + foreach ($innerFields as $key => $field) { + if (is_numeric($key) === false || $key === 0) { + return __('All the \'%s\' block parameters must use numbers greater than 0 as keys: \'%s\'.', $customField, $key); + } + + foreach ($requiredKeys as $k => $value) { + if (empty($field[$value]) === true) { + return __('The \'%s\' block \'%s\' parameter definitions can not be empty: \'%s\'.', $customField, $value, $key); + } + } + + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $field['macro'])) { + return __('The \'%s\' block \'macro\' parameter has a definition with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', $customField, $field['macro']); + } + + if (in_array($field['type'], $validTypes) === false) { + return __('The \'%s\' block \'type\' parameter has a definition with invalid value. Must be \'string\', \'number\', \'password\', \'textarea\', \'checkbox\', \'select\', \'multiselect\' or \'tree\': \'%s\'', $customField, $field['type']); + } + + if ($field['type'] === 'select' || $field['type'] === 'multiselect') { + if (empty($field['select_data']) === true) { + return __('All the \'%s\' block \'select_data\' parameter definitions can not be empty: \'%s\'.', $customField, $key); + } else if ($iniForValidate[$field['select_data']] === null && in_array($field['select_data'], $validSelectData) === false) { + return __( + 'The \'%s\' block \'select_data\' parameter has a definition with invalid select type. Must be \'agent_groups\', \'agents\', \'module_groups\', \'modules\', \'module_types\', \'tags\', \'status\', \'alert_templates\', \'alert_actions\', \'interval\', \'credentials.custom\', \'credentials.aws\', \'credentials.azure\', \'credentials.gcp\', \'credentials.sap\', \'credentials.snmp\', \'os\' or an existint reference: \'%s\'', + $customField, + $field['select_data'] + ); + } else if ($iniForValidate[$field['select_data']] !== null) { + $selectDataNames[] = $field['select_data']; + } + } + + if ($field['type'] === 'tree') { + if (empty($field['tree_data']) === true) { + return __('All the \'%s\' block \'tree_data\' parameter definitions can not be empty: \'%s\'', $field['macro'], $key); + } else if ($iniForValidate[$field['tree_data']] === null) { + return __('The \'%s\' block \'tree_data\' parameter has a key value reference that does not exist: \'%s\'', $customField, $field['tree_data']); + } else { + $treeDataNames[] = $field['tree_data']; + } + } + + if (empty($field['mandatory_field']) === false) { + $validValues = [ + 'true', + 'false', + '1', + '0', + 'yes', + 'no', + ]; + + if (in_array($field['mandatory_field'], $validValues) === false) { + return __( + 'The \'%s\' block \'mandatory_field\' parameter has a definition with invalid value. Must be \'true\' or \'false\', \'1\' or \'0\', \'yes\' or \'no\': \'%s\'', + $customField, + $field['mandatory_field'] + ); + } + } + + if ($field['tip'] !== null && empty($field['tip']) === true) { + return __('All the \'%s\' block \'tip\' parameter definitions can not be empty: \'%s\'.', $customField, $key); + } + + if ($field['placeholder'] !== null && empty($field['placeholder']) === true) { + return __('All the \'%s\' block \'placeholder\' parameter definitions can not be empty: \'%s\'.', $customField, $key); + } + + if (empty($field['show_on_true']) === false) { + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $field['show_on_true'])) { + return __( + 'The \'%s\' block \'show_on_true\' parameter has a definition with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', + $customField, + $field['show_on_true'] + ); + } + } + + if (empty($field['encrypt_on_true']) === false) { + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $field['encrypt_on_true'])) { + return __( + 'The \'%s\' block \'encrypt_on_true\' parameter has a definition with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', + $customField, + $field['encrypt_on_true'] + ); + } + } + } + } + + foreach ($treeDataNames as $key => $name) { + $error = self::validateTreeRecursive($name, $iniForValidate); + if ($error !== false) { + return $error; + } + } + + foreach ($selectDataNames as $key => $name) { + if (empty($iniForValidate[$name]['option']) === true) { + return __('The \'%s\' block must contain an \'option\' parameter', $name); + } + + foreach ($iniForValidate[$name]['option'] as $key => $option) { + if (empty($option) === true) { + return __('All the \'%s\' block \'option\' parameter definitions can not be empty: \'%s\'.', $name, $key); + } + } + } + + if ($iniForValidate['tempfile_confs'] !== null && empty($iniForValidate['tempfile_confs']['file']) === true) { + return __('The \'tempfile_confs\' block must contain a \'file\' parameter.'); + } + + foreach ($iniForValidate['tempfile_confs']['file'] as $key => $tempfile) { + if (!preg_match('/^_[a-zA-Z0-9]+_$/', $key)) { + return __( + 'The \'tempfile_confs\' block \'file\' parameter has a key with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', + $key + ); + } + + if (empty($tempfile) === true) { + return __('All the \'tempfile_confs\' block \'file\' parameter definitions can not be empty: \'%s\'.', $key); + } + } + + return false; + } + + + /** + * Validate a tree recursively + * + * @param string $dataTree Name of parent data_tree. + * @param array $iniFile Inifile for search children. + * @param array $parents Array of parents for recursive action, DO NOT SET. + * + * @return boolean True if tree is correct. + */ + public static function validateTreeRecursive($dataTree, $iniFile, $parents=[]) + { + $innerData = []; + $parents[] = $dataTree; + foreach ($iniFile[$dataTree] as $key => $value) { + foreach ($value as $innerKey => $innerValue) { + if (isset($innerData[$innerKey])) { + $innerData[$innerKey][$key] = $innerValue; + } else { + $innerData[$innerKey] = [$key => $innerValue]; + } + } + } + + if (count($innerData) === 0) { + return __('The \'%s\' block must contain a \'name\' parameter that can not be empty.', $dataTree); + } + + foreach ($innerData as $key => $prop) { + if (is_numeric($key) === false || $key === 0) { + return __('All the \'%s\' block parameters must use numbers greater than 0 as keys: \'%s\'.', $dataTree, $key); + } + + if (empty($prop['name']) === true) { + return __('The \'%s\' block must contain a \'name\' parameter for all the tree elements: \'%s\'.', $dataTree, $key); + } + + if ($prop['selectable'] !== null && $prop['selectable'] === '') { + return __('All the \'%s\' block \'selectable\' parameter definitions can not be empty: \'%s\'.', $dataTree, $key); + } else { + $validValues = [ + 'true', + 'false', + '1', + '0', + 'yes', + 'no', + ]; + + if (in_array($prop['selectable'], $validValues) === false) { + return __( + 'The \'%s\' block \'selectable\' parameter has a definition with invalid value. Must be \'true\' or \'false\', \'1\' or \'0\', \'yes\' or \'no\': \'%s\'', + $dataTree, + $prop['selectable'] + ); + } + } + + if ($prop['macro'] !== null && !preg_match('/^_[a-zA-Z0-9]+_$/', $prop['macro'])) { + return __( + 'The \'%s\' block \'macro\' parameter has a definition with invalid format. Use only letters (A-Z and a-z) and numbers (0-9) between opening and ending underscores (_): \'%s\'', + $dataTree, + $prop['macro'] + ); + } + + if ($prop['children'] !== null && empty($iniFile[$prop['children']]) === true) { + return __('The \'%s\' block \'children\' parameter has a key value reference that does not exist: \'%s\'', $dataTree, $prop['children']); + } else if (in_array($prop['children'], $parents) === true) { + return __('The \'%s\' block \'children\' parameter has a key value reference to a parent tree element: \'%s\'', $dataTree, $prop['children']); + } else if (empty($iniFile[$prop['children']]) === false) { + $result = self::validateTreeRecursive($prop['children'], $iniFile, $parents); + if ($result !== false) { + return $result; + } + } + } + + return false; + } + + + /** + * Excute command with the timeout of the task. + * + * @param string $command Command to execute. + * + * @return string Output of command + */ + private function executeCommand($command) + { + $task = $this->getTask(); + $timeout = $task['executions_timeout']; + + $descriptors = [ + 0 => [ + 'pipe', + 'r', + ], + 1 => [ + 'pipe', + 'w', + ], + 2 => [ + 'pipe', + 'w', + ], + ]; + + $process = proc_open($command, $descriptors, $pipes); + + if (!is_resource($process)) { + return false; + } + + stream_set_blocking($pipes[1], 0); + + stream_set_blocking($pipes[2], 0); + + if (!$timeout) { + $timeout = 5; + } + + $real_timeout = ($timeout * 1000000); + + $buffer = ''; + + while ($real_timeout > 0) { + $start = microtime(true); + + $read = [$pipes[1]]; + $other = []; + stream_select($read, $other, $other, 0, $real_timeout); + + $status = proc_get_status($process); + + $buffer .= stream_get_contents($pipes[1]); + + if ($status['running'] === false) { + break; + } + + $real_timeout -= ((microtime(true) - $start) * 1000000); + } + + if ($real_timeout <= 0) { + proc_terminate($process, 9); + + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + proc_close($process); + + return false; + } + + $errors = stream_get_contents($pipes[2]); + + if (empty($errors) === false && empty($buffer)) { + proc_terminate($process, 9); + + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + proc_close($process); + + return false; + } + + proc_terminate($process, 9); + + fclose($pipes[0]); + fclose($pipes[1]); + fclose($pipes[2]); + + proc_close($process); + + return $buffer; + } + + +} diff --git a/pandora_console/include/class/SatelliteAgent.class.php b/pandora_console/include/class/SatelliteAgent.class.php index 31cd2550d9..29fa2e3b77 100644 --- a/pandora_console/include/class/SatelliteAgent.class.php +++ b/pandora_console/include/class/SatelliteAgent.class.php @@ -162,7 +162,7 @@ class SatelliteAgent extends HTML [ 'id' => $this->tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, diff --git a/pandora_console/include/class/SatelliteCollection.class.php b/pandora_console/include/class/SatelliteCollection.class.php index 8af5f210c8..a1ef24393c 100644 --- a/pandora_console/include/class/SatelliteCollection.class.php +++ b/pandora_console/include/class/SatelliteCollection.class.php @@ -142,7 +142,7 @@ class SatelliteCollection extends HTML [ 'id' => $this->tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, diff --git a/pandora_console/include/class/SnmpConsole.class.php b/pandora_console/include/class/SnmpConsole.class.php index e613ab57bf..4a2c32de2e 100644 --- a/pandora_console/include/class/SnmpConsole.class.php +++ b/pandora_console/include/class/SnmpConsole.class.php @@ -326,7 +326,7 @@ class SnmpConsole extends HTML [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $this->ajaxController, @@ -519,6 +519,8 @@ class SnmpConsole extends HTML $legend .= ''; $legend .= ''; + echo '
'; + ui_toggle($legend, __('Legend')); // Load own javascript file. @@ -1331,17 +1333,8 @@ class SnmpConsole extends HTML * Show more information */ function toggleVisibleExtendedInfo(id, position) { - // Show all "Show more" - $('[id^=img_]').each(function() { - $(this).show(); - }); - // Hide all "Hide details" - $('[id^=img_hide_]').each(function() { - $(this).hide(); - }); var status = $('#eye_'+id).attr('data-show'); if(status == "show"){ - $('tr[id^=show_]').remove() $.ajax({ method: 'get', url: '', @@ -1360,14 +1353,14 @@ class SnmpConsole extends HTML datatype: "json", success: function(data) { let trap = JSON.parse(data); - var tr = $('#snmp_console tr').eq(position+1); + var tr = $('#snmp_console tr:not([id^="show_"])').eq(position+1); // Count. if ($('#filter_group_by').val() == 1) { let labelCount = '

'; let variableCount = `${trap['count']}
${trap['first']}
${trap['last']}`; - tr.after(`${labelCount}${variableCount}`); + tr.after(`${labelCount}${variableCount}`); } // Type. @@ -1405,27 +1398,27 @@ class SnmpConsole extends HTML let labelType = ''; let variableType = `${desc_trap_type}`; - tr.after(`${labelType}${variableType}`); + tr.after(`${labelType}${variableType}`); // Description. if (trap['description']) { let labelDesc = ''; let variableDesc = `${trap['description']}`; - tr.after(`${labelDesc}${variableDesc}`); + tr.after(`${labelDesc}${variableDesc}`); } // Enterprise String. let labelOid = ''; let variableOId = `${trap['oid']}`; - tr.after(`${labelOid}${variableOId}`); + tr.after(`${labelOid}${variableOId}`); // Variable bindings. let labelBindings = ''; let variableBindings = ''; if ($('#filter_group_by').val() == 1) { - labelBindings = ''; + labelBindings = ''; let new_url = 'index.php?sec=snmpconsole&sec2=operation/snmpconsole/snmp_view'; new_url += '&filter_severity='+$('#filter_severity').val(); @@ -1439,7 +1432,7 @@ class SnmpConsole extends HTML variableBindings = `${string}`; } else { - labelBindings = ''; + labelBindings = ''; const binding_vars = trap['oid_custom'].split("\t"); let string = ''; binding_vars.forEach(function(oid) { @@ -1448,7 +1441,7 @@ class SnmpConsole extends HTML variableBindings = `${string}`; } - tr.after(`${labelBindings}${variableBindings}`); + tr.after(`${labelBindings}${variableBindings}`); }, error: function(e) { console.error(e); @@ -1458,7 +1451,7 @@ class SnmpConsole extends HTML $('#img_'+id).hide(); $('#img_hide_'+id).show(); } else{ - $('tr[id^=show_]').remove(); + $(`tr#show_${id}`).remove(); $('#eye_'+id).attr('data-show', 'show'); $('#img_'+id).show(); $('#img_hide_'+id).hide(); diff --git a/pandora_console/include/class/TipsWindow.class.php b/pandora_console/include/class/TipsWindow.class.php index cf0824f626..ae4271fba9 100644 --- a/pandora_console/include/class/TipsWindow.class.php +++ b/pandora_console/include/class/TipsWindow.class.php @@ -475,7 +475,7 @@ class TipsWindow [ 'id' => 'list_tips_windows', 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'dom_elements' => 'lpfti', 'filter_main_class' => 'box-flat white_table_graph fixed_filter_bar', 'columns' => $columns, diff --git a/pandora_console/include/config_process.php b/pandora_console/include/config_process.php index 20d3363e68..6a14082ea7 100644 --- a/pandora_console/include/config_process.php +++ b/pandora_console/include/config_process.php @@ -20,7 +20,7 @@ /** * Pandora build version and version */ -$build_version = 'PC230719'; +$build_version = 'PC230727'; $pandora_version = 'v7.0NG.772'; // Do not overwrite default timezone set if defined. diff --git a/pandora_console/include/constants.php b/pandora_console/include/constants.php index 64260179ce..e8d4eb3a4f 100644 --- a/pandora_console/include/constants.php +++ b/pandora_console/include/constants.php @@ -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); diff --git a/pandora_console/include/functions.php b/pandora_console/include/functions.php index ee4ee7d1ab..e8f0ac3452 100644 --- a/pandora_console/include/functions.php +++ b/pandora_console/include/functions.php @@ -907,7 +907,7 @@ function set_cookie($name, $value) { if (is_null($value)) { unset($_COOKIE[$value]); - setcookie($name, null, -1, '/'); + setcookie($name, '', -1, '/'); } else { setcookie($name, $value); } diff --git a/pandora_console/include/functions_config.php b/pandora_console/include/functions_config.php index f98dae5bf9..9ba72c9d28 100644 --- a/pandora_console/include/functions_config.php +++ b/pandora_console/include/functions_config.php @@ -378,6 +378,10 @@ function config_update_config() $error_update[] = __('keep_in_process_status_extra_id'); } + if (config_update_value('show_experimental_features', get_parameter('show_experimental_features'), true) === false) { + $error_update[] = __('show_experimental_features'); + } + if (config_update_value('console_log_enabled', get_parameter('console_log_enabled'), true) === false) { $error_update[] = __('Console log enabled'); } @@ -978,10 +982,6 @@ function config_update_config() $error_update[] = __('Max. days before delete old messages'); } - if (config_update_value('delete_old_network_matrix', get_parameter('delete_old_network_matrix'), true) === false) { - $error_update[] = __('Max. days before delete old network matrix data'); - } - if (config_update_value('max_graph_container', get_parameter('max_graph_container'), true) === false) { $error_update[] = __('Graph container - Max. Items'); } @@ -2239,10 +2239,6 @@ function config_process_config() config_update_value('delete_old_messages', 21); } - if (!isset($config['delete_old_network_matrix'])) { - config_update_value('delete_old_network_matrix', 10); - } - if (!isset($config['max_graph_container'])) { config_update_value('max_graph_container', 10); } @@ -2405,6 +2401,10 @@ function config_process_config() config_update_value('keep_in_process_status_extra_id', 0); } + if (!isset($config['show_experimental_features'])) { + config_update_value('show_experimental_features', 0); + } + if (!isset($config['console_log_enabled'])) { config_update_value('console_log_enabled', 0); } @@ -2510,10 +2510,6 @@ function config_process_config() 'max' => 90, 'min' => 0, ], - 'delete_old_network_matrix' => [ - 'max' => 30, - 'min' => 1, - ], 'report_limit' => [ 'max' => 500, 'min' => 1, @@ -3479,10 +3475,6 @@ function config_process_config() config_update_value('dbtype', 'mysql'); } - if (!isset($config['legacy_vc'])) { - config_update_value('legacy_vc', 0); - } - if (!isset($config['vc_default_cache_expiration'])) { config_update_value('vc_default_cache_expiration', 60); } diff --git a/pandora_console/include/functions_graph.php b/pandora_console/include/functions_graph.php index ddf68475c6..c35e553235 100644 --- a/pandora_console/include/functions_graph.php +++ b/pandora_console/include/functions_graph.php @@ -4624,7 +4624,10 @@ function graph_netflow_circular_mesh($data) include_once $config['homedir'].'/include/graphs/functions_d3.php'; - return d3_relationship_graph($data['elements'], $data['matrix'], 900, true); + $width = (empty($data['width']) === false) ? $data['width'] : 900; + $height = (empty($data['height']) === false) ? $data['height'] : 900; + + return d3_relationship_graph($data['elements'], $data['matrix'], $width, true, $height); } diff --git a/pandora_console/include/functions_html.php b/pandora_console/include/functions_html.php index 28bd9d4fb8..4862705545 100644 --- a/pandora_console/include/functions_html.php +++ b/pandora_console/include/functions_html.php @@ -5507,7 +5507,10 @@ function html_print_input($data, $wrapper='div', $input_only=false) ($data['attributes'] ?? null), ((isset($data['return']) === true) ? $data['return'] : false), ((isset($data['password']) === true) ? $data['password'] : false), - ((isset($data['function']) === true) ? $data['function'] : '') + ((isset($data['function']) === true) ? $data['function'] : ''), + ((isset($data['autocomplete']) === true) ? $data['autocomplete'] : 'off'), + ((isset($data['disabled']) === true) ? $data['disabled'] : false), + ((isset($data['hide_div_eye']) === true) ? $data['hide_div_eye'] : false), ); break; diff --git a/pandora_console/include/functions_menu.php b/pandora_console/include/functions_menu.php index ff18544586..143a538e20 100644 --- a/pandora_console/include/functions_menu.php +++ b/pandora_console/include/functions_menu.php @@ -353,7 +353,7 @@ function menu_print_menu(&$menu) $secExtensionBool = false; if ($secExtensionBool) { - if (strlen($sub['icon']) > 0) { + if (empty($sub['icon']) === false && strlen($sub['icon']) > 0) { $icon_enterprise = false; if (isset($sub['enterprise'])) { $icon_enterprise = (bool) $sub['enterprise']; @@ -380,7 +380,7 @@ function menu_print_menu(&$menu) $secExtension = $sub['sec']; } - if (strlen($secExtension) > 0) { + if (empty($secExtension) === false && strlen($secExtension) > 0) { $secUrl = $secExtension; $extensionInMenu = 'extension_in_menu='.$mainsec.'&'; } else { diff --git a/pandora_console/include/functions_netflow.php b/pandora_console/include/functions_netflow.php index 1cf3a5b960..79fcd9a0db 100644 --- a/pandora_console/include/functions_netflow.php +++ b/pandora_console/include/functions_netflow.php @@ -1233,7 +1233,9 @@ function netflow_draw_item( $max_aggregates, $connection_name='', $output='HTML', - $address_resolution=false + $address_resolution=false, + $width_content=false, + $height_content=false ) { $aggregate = $filter['aggregate']; $interval = ($end_date - $start_date); @@ -1432,6 +1434,9 @@ function netflow_draw_item( netflow_aggregate_is_ip($aggregate) ); + $data_circular['width'] = $width_content; + $data_circular['height'] = $height_content; + $html = '
'; $html .= graph_netflow_circular_mesh($data_circular); $html .= '
'; diff --git a/pandora_console/include/functions_ui.php b/pandora_console/include/functions_ui.php index 0f1712242c..eb033bfec6 100755 --- a/pandora_console/include/functions_ui.php +++ b/pandora_console/include/functions_ui.php @@ -3742,28 +3742,71 @@ function ui_progress_extend( * Generate needed code to print a datatables jquery plugin. * * @param array $parameters All desired data using following format: - * [ - * 'print' => true (by default printed) - * 'id' => datatable id. - * 'class' => datatable class. - * 'style' => datatable style. - * 'order' => [ - * 'field' => column name - * 'direction' => asc or desc - * ], - * 'default_pagination' => integer, default pagination is set to block_size - * 'ajax_url' => 'include/ajax.php' ajax_url. - * 'ajax_data' => [ operation => 1 ] extra info to be sent. - * 'ajax_postprocess' => a javscript function to postprocess data received - * by ajax call. It is applied foreach row and must - * use following format: - * * [code] - * * function (item) { - * * // Process received item, for instance, name: - * * tmp = '' + item.name + ''; - * * item.name = tmp; - * * } - * * [/code] + * + * ```php + * $parameters = [ + * // JS Parameters + * 'serverside' => true, + * 'paging' => true, + * 'default_pagination' => $config['block_size'], + * 'searching' => false, + * 'dom_elements' => "plfrtiB", + * 'pagination_options' => [default_pagination, 5, 10, 20, 100, 200, 500, 1000, "All"], + * 'ordering' => true, + * 'order' => [[0, "asc"]], //['field' => 'column_name', 'direction' => 'asc/desc'] + * 'zeroRecords' => "No matching records found", + * 'emptyTable' => "No data available in table", + * 'no_sortable_columns' => [], //Allows the column name (db) from "columns" parameter + * 'csv_field_separator' => ",", + * 'csv_header' => true, + * 'mini_csv' => false, + * 'mini_pagination' => false, + * 'mini_search' => false, + * 'drawCallback' => undefined, //'console.log(123),' + * 'data_element' => undefined, //Rows processed + * 'ajax_postprocess' => undefined, //'process_datatables_item(item)' + * 'ajax_data' => undefined, //Extra data to be sent ['field1' => 1, 'field2 => 0] + * 'ajax_url' => undefined, + * 'caption' => undefined, + * + * // PHP Parameters + * 'id' => undefined, //Used for table and form id, + * 'columns' =>, + * 'column_names' =>, + * 'filter_main_class' =>, + * 'toggle_collapsed' =>true, + * 'search_button_class' => 'sub filter', + * 'csv' =>=1, + * 'form' => + * ..[ + * ....'id' => $form_id, + * ....'class' => 'flex-row', + * ....'style' => 'width: 100%,', + * ....'js' => '', + * ....'html' => $filter, + * ....'inputs' => [], + * ....'extra_buttons' => $buttons, + * ..], + * 'no_toggle' => false, + * 'form_html' => undefined, + * 'toggle_collapsed' => true, + * 'class' => "", //Datatable class. + * 'style' => "" ,//Datatable style. + * 'return' => false, + * 'print' => true, + * ] + * + * ``` + * + * ```php + * ajax_postprocess => a javscript function to postprocess data received + * by ajax call. It is applied foreach row and must + * use following format: + * function (item) { + * // Process received item, for instance, name: + * tmp = '' + item.name + ''; + * item.name = tmp; + * } * 'columns_names' => [ * 'column1' :: Used as th text. Direct text entry. It could be array: * OR @@ -3780,7 +3823,6 @@ function ui_progress_extend( * 'column2', * ... * ], - * 'no_sortable_columns' => [ indexes ] 1,2... -1 etc. Avoid sorting. * 'form' => [ * 'html' => 'html code' a directly defined inputs in HTML. * 'extra_buttons' => [ @@ -3812,12 +3854,7 @@ function ui_progress_extend( * ] * ], * 'extra_html' => HTML content to be placed after 'filter' section. - * 'drawCallback' => function to be called after draw. Sample in: - * https://datatables.net/examples/advanced_init/row_grouping.html - * ] - * 'zeroRecords' => Message when zero records obtained from filter.(Leave blank for default). - * 'emptyTable' => Message when table data empty.(Leave blank for default). - * End. + * ``` * * @return string HTML code with datatable. * @throws Exception On error. @@ -3834,6 +3871,9 @@ function ui_print_datatable(array $parameters) $form_id = uniqid('datatable_filter_'); } + $parameters['table_id'] = $table_id; + $parameters['form_id'] = $form_id; + if (!isset($parameters['columns']) || !is_array($parameters['columns'])) { throw new Exception('[ui_print_datatable]: You must define columns for datatable'); } @@ -3853,10 +3893,6 @@ function ui_print_datatable(array $parameters) $parameters['default_pagination'] = $config['block_size']; } - if (!isset($parameters['paging'])) { - $parameters['paging'] = true; - } - if (!isset($parameters['filter_main_class'])) { $parameters['filter_main_class'] = ''; } @@ -3865,13 +3901,9 @@ function ui_print_datatable(array $parameters) $parameters['toggle_collapsed'] = true; } - $no_sortable_columns = json_encode([]); - if (isset($parameters['no_sortable_columns'])) { - $no_sortable_columns = json_encode($parameters['no_sortable_columns']); - } - if (!is_array($parameters['order'])) { - $order = '0, "asc"'; + $order = 0; + $direction = 'asc'; } else { if (!isset($parameters['order']['direction'])) { $direction = 'asc'; @@ -3890,47 +3922,35 @@ function ui_print_datatable(array $parameters) } } - $order .= ', "'.$parameters['order']['direction'].'"'; + $direction = $parameters['order']['direction']; } - if (!isset($parameters['ajax_data'])) { - $parameters['ajax_data'] = ''; + $parameters['order']['order'] = $order; + $parameters['order']['direction'] = $direction; + + foreach ($parameters['no_sortable_columns'] as $key => $find) { + $found = array_search( + $parameters['no_sortable_columns'][$key], + $parameters['columns'] + ); + + if ($found !== false) { + unset($parameters['no_sortable_columns'][$key]); + array_push($parameters['no_sortable_columns'], $found); + } + + if (is_int($parameters['no_sortable_columns'][$key]) === false) { + unset($parameters['no_sortable_columns'][$key]); + } } - $search_button_class = 'sub filter'; + $parameters['csvTextInfo'] = __('Export current page to CSV'); + $parameters['csvFileTitle'] = sprintf(__('export_%s_current_page_%s'), $table_id, date('Y-m-d')); + if (isset($parameters['search_button_class'])) { $search_button_class = $parameters['search_button_class']; - } - - if (isset($parameters['pagination_options'])) { - $pagination_options = $parameters['pagination_options']; } else { - $pagination_options = [ - [ - // There is a limit of (2^32)^2 (18446744073709551615) rows in a MyISAM table, show for show all use max nrows. - // -1 Retun error or only 1 row. - $parameters['default_pagination'], - 5, - 10, - 25, - 100, - 200, - 500, - 1000, - 18446744073709551615, - ], - [ - $parameters['default_pagination'], - 5, - 10, - 25, - 100, - 200, - 500, - 1000, - 'All', - ], - ]; + $search_button_class = 'sub filter'; } if (isset($parameters['datacolumns']) === false @@ -3943,16 +3963,12 @@ function ui_print_datatable(array $parameters) $parameters['csv'] = 1; } - $dom_elements = '"plfrtiB"'; - if (isset($parameters['dom_elements'])) { - $dom_elements = '"'.$parameters['dom_elements'].'"'; - } - $filter = ''; // Datatable filter. if (isset($parameters['form']) && is_array($parameters['form'])) { if (isset($parameters['form']['id'])) { $form_id = $parameters['form']['id']; + $parameters['form_id'] = $form_id; } if (isset($parameters['form']['class'])) { @@ -4070,10 +4086,13 @@ function ui_print_datatable(array $parameters) ) ); $processing .= ''; + $parameters['processing'] = $processing; $zeroRecords = isset($parameters['zeroRecords']) === true ? $parameters['zeroRecords'] : __('No matching records found'); $emptyTable = isset($parameters['emptyTable']) === true ? $parameters['emptyTable'] : __('No data available in table'); + $parameters['zeroRecords'] = $zeroRecords; + $parameters['emptyTable'] = $emptyTable; // Extra html. $extra = ''; if (isset($parameters['extra_html']) && !empty($parameters['extra_html'])) { @@ -4082,8 +4101,8 @@ function ui_print_datatable(array $parameters) // Base table. $table = ''; + $table .= 'class="'.$parameters['class'].'"'; + $table .= 'style="box-sizing: border-box;'.$parameters['style'].'">'; $table .= ''; if (isset($parameters['column_names']) @@ -4110,336 +4129,60 @@ function ui_print_datatable(array $parameters) } $table .= ''; - - if (isset($parameters['data_element']) === true) { - $table .= ''; - foreach ($parameters['data_element'] as $row) { - $table .= ''; - foreach ($row as $td_data) { - $table .= ''; - } - - $table .= ''; - } - - $table .= ''; - - $js = ''; - } - $table .= '
'.$td_data.'
'; - $pagination_class = 'pandora_pagination'; - if (!empty($parameters['pagination_class'])) { - $pagination_class = $parameters['pagination_class']; + $parameters['ajax_url_full'] = ui_get_full_url('ajax.php', false, false, false); + + $parameters['spinnerLoading'] = html_print_image( + 'images/spinner.gif', + true, + [ + 'id' => $form_id.'_loading', + 'class' => 'loading-search-datatables-button', + ] + ); + + $language = substr(get_user_language(), 0, 2); + if (is_metaconsole() === false) { + $parameters['language'] = 'include/javascript/i18n/dataTables.'.$language.'.json'; + } else { + $parameters['language'] = '../../include/javascript/i18n/dataTables.'.$language.'.json'; } - $columns = ''; - for ($i = 1; $i <= (count($parameters['columns']) - 3); $i++) { - if ($i != (count($parameters['columns']) - 3)) { - $columns .= $i.','; - } else { - $columns .= $i; - } + $parameters['phpDate'] = date('Y-m-d'); + $parameters['dataElements'] = json_encode($parameters['data_element']); + + // * START JAVASCRIPT. + if (is_metaconsole() === false) { + $file_path = ui_get_full_url('include/javascript/datatablesFunction.js'); + } else { + $file_path = ui_get_full_url('../../include/javascript/datatablesFunction.js'); } - $export_columns = ''; - if (isset($parameters['csv_exclude_latest']) === true - && $parameters['csv_exclude_latest'] === true - ) { - $export_columns = ',columns: \'th:not(:last-child)\''; - } + $file_content = file_get_contents($file_path); + $json_data = json_encode($parameters); + $json_config = json_encode($config); - if (isset($parameters['data_element']) === false || isset($parameters['print_pagination_search_csv'])) { - if (isset($parameters['ajax_url'])) { - $type_data = 'ajax: { - url: "'.ui_get_full_url('ajax.php', false, false, false).'", - type: "POST", - dataSrc: function (json) { - if($("#'.$form_id.'_search_bt") != undefined) { - $("#'.$form_id.'_loading").remove(); - } + $js = ''; - if (json.error) { - console.error(json.error); - $("#error-'.$table_id.'").html(json.error); - $("#error-'.$table_id.'").dialog({ - title: "Filter failed", - width: 630, - resizable: true, - draggable: true, - modal: false, - closeOnEscape: true, - buttons: { - "Ok" : function () { - $(this).dialog("close"); - } - } - }).parent().addClass("ui-state-error"); - } else {'; - - if (isset($parameters['ajax_return_operation']) === true - && empty($parameters['ajax_return_operation']) === false - && isset($parameters['ajax_return_operation_function']) === true - && empty($parameters['ajax_return_operation_function']) === false - ) { - $type_data .= ' - if (json.'.$parameters['ajax_return_operation'].' !== undefined) { - '.$parameters['ajax_return_operation_function'].'(json.'.$parameters['ajax_return_operation'].'); - } - '; - } - - if (isset($parameters['ajax_postprocess'])) { - $type_data .= ' - if (json.data) { - json.data.forEach(function(item) { - '.$parameters['ajax_postprocess'].' - }); - } else { - json.data = {}; - }'; - } - - $type_data .= ' - return json.data; - } - }, - data: function (data) { - if($("#button-'.$form_id.'_search_bt") != undefined) { - var loading = \''.html_print_image( - 'images/spinner.gif', - true, - [ - 'id' => $form_id.'_loading', - 'class' => 'loading-search-datatables-button', - ] - ).'\'; - $("#button-'.$form_id.'_search_bt").parent().append(loading); - } - - inputs = $("#'.$form_id.' :input"); - - values = {}; - inputs.each(function() { - values[this.name] = $(this).val(); - }) - - $.extend(data, { - filter: values,'."\n"; - - if (is_array($parameters['ajax_data'])) { - foreach ($parameters['ajax_data'] as $k => $v) { - $type_data .= $k.':'.json_encode($v).",\n"; - } - } - - $type_data .= 'page: "'.$parameters['ajax_url'].'" - }); - - return data; - } - },'; - } else { - $type_data = 'data: '.json_encode($parameters['data_element']).','; - } - - $serverside = 'true'; - if (isset($parameters['data_element'])) { - $serverside = 'false'; - } - - // Javascript controller. - $js = ''; - } - - // Order. + $js .= ''; + // * END JAVASCRIPT. $info_msg_arr = []; $info_msg_arr['message'] = $emptyTable; $info_msg_arr['div_class'] = 'info_box_container invisible_important datatable-msg-info-'.$table_id; - $spinner = '
'; + $spinner = '
'; $info_msg = '
'.ui_print_info_message($info_msg_arr).'
'; + $err_msg = '
'; $output = $info_msg.$err_msg.$filter.$extra.$spinner.$table.$js; if (is_ajax() === false) { @@ -4463,7 +4206,7 @@ function ui_print_datatable(array $parameters) false, false ); - $output .= '?v='.$config['current_package'].'"/>'; + $output .= '"/>'; // Load tables.css. $output .= ''; + } else { + $output .= '
'; + + return $output; +} + + function ui_update_name_fav_element($id_element, $section, $label) { $label = io_safe_output($label); diff --git a/pandora_console/include/functions_visual_map_editor.php b/pandora_console/include/functions_visual_map_editor.php index f99484df1f..0170da7f07 100755 --- a/pandora_console/include/functions_visual_map_editor.php +++ b/pandora_console/include/functions_visual_map_editor.php @@ -1274,52 +1274,50 @@ function visual_map_editor_print_item_palette($visualConsole_id, $background) ); $form_items_advance['element_group_row']['html'] .= ''; - if (!$config['legacy_vc']) { - $intervals = [ - 10 => '10 '.__('seconds'), - 30 => '30 '.__('seconds'), - 60 => '1 '.__('minutes'), - 300 => '5 '.__('minutes'), - 900 => '15 '.__('minutes'), - 1800 => '30 '.__('minutes'), - 3600 => '1 '.__('hour'), - ]; + $intervals = [ + 10 => '10 '.__('seconds'), + 30 => '30 '.__('seconds'), + 60 => '1 '.__('minutes'), + 300 => '5 '.__('minutes'), + 900 => '15 '.__('minutes'), + 1800 => '30 '.__('minutes'), + 3600 => '1 '.__('hour'), + ]; - $form_items_advance['cache_expiration_row'] = []; - $form_items_advance['cache_expiration_row']['items'] = [ - 'static_graph', - 'percentile_bar', - 'percentile_item', - 'module_graph', - 'simple_value', - 'datos', - 'auto_sla_graph', - 'group_item', - 'bars_graph', - 'donut_graph', - 'color_cloud', - 'service', - ]; - $form_items_advance['cache_expiration_row']['html'] = ''; - $form_items_advance['cache_expiration_row']['html'] .= __('Cache expiration'); - $form_items_advance['cache_expiration_row']['html'] .= ''; - $form_items_advance['cache_expiration_row']['html'] .= ''; - $form_items_advance['cache_expiration_row']['html'] .= html_print_extended_select_for_time( - 'cache_expiration', - $config['vc_default_cache_expiration'], - '', - __('No cache'), - 0, - false, - true, - false, - true, - '', - false, - $intervals - ); - $form_items_advance['cache_expiration_row']['html'] .= ''; - } + $form_items_advance['cache_expiration_row'] = []; + $form_items_advance['cache_expiration_row']['items'] = [ + 'static_graph', + 'percentile_bar', + 'percentile_item', + 'module_graph', + 'simple_value', + 'datos', + 'auto_sla_graph', + 'group_item', + 'bars_graph', + 'donut_graph', + 'color_cloud', + 'service', + ]; + $form_items_advance['cache_expiration_row']['html'] = ''; + $form_items_advance['cache_expiration_row']['html'] .= __('Cache expiration'); + $form_items_advance['cache_expiration_row']['html'] .= ''; + $form_items_advance['cache_expiration_row']['html'] .= ''; + $form_items_advance['cache_expiration_row']['html'] .= html_print_extended_select_for_time( + 'cache_expiration', + $config['vc_default_cache_expiration'], + '', + __('No cache'), + 0, + false, + true, + false, + true, + '', + false, + $intervals + ); + $form_items_advance['cache_expiration_row']['html'] .= ''; // Insert and modify before the buttons to create or update. if (enterprise_installed()) { @@ -1454,12 +1452,9 @@ function visual_map_editor_print_toolbox() visual_map_print_button_editor('box_item', __('Box'), 'left', false, 'box_item', true); visual_map_print_button_editor('line_item', __('Line'), 'left', false, 'line_item', true); visual_map_print_button_editor('color_cloud', __('Color cloud'), 'left', false, 'color_cloud_min', true); - if (isset($config['legacy_vc']) === false - || (bool) $config['legacy_vc'] === false - ) { - // Applies only on modern VC. - visual_map_print_button_editor('network_link', __('Network link'), 'left', false, 'network_link_min', true); - } + + // Applies only on modern VC. + visual_map_print_button_editor('network_link', __('Network link'), 'left', false, 'network_link_min', true); if (defined('METACONSOLE')) { echo ' - chordDiagram('#chord_diagram', $elements, $matrix, $width); + chordDiagram('#chord_diagram', $elements, $matrix, $width, $height); "; if (!$return) { diff --git a/pandora_console/include/graphs/functions_flot.php b/pandora_console/include/graphs/functions_flot.php index bce475ad4f..6b64cae989 100644 --- a/pandora_console/include/graphs/functions_flot.php +++ b/pandora_console/include/graphs/functions_flot.php @@ -259,7 +259,7 @@ function flot_area_graph( $return .= html_print_input_hidden( 'line_width_graph', - $config['custom_graph_width'], + (empty($params['line_width']) === true) ? $config['custom_graph_width'] : $params['line_width'], true ); $return .= "
a, a => b, a => c] // [5, 0, 1], // b[b => a, b => b, b => c] // [2, 3, 0]]; // c[c => a, c => b, c => c] -function chordDiagram(recipient, elements, matrix, width) { +function chordDiagram(recipient, elements, matrix, width, height) { d3.chart = d3.chart || {}; d3.chart.chordWheel = function(options) { // Default values @@ -59,10 +59,13 @@ function chordDiagram(recipient, elements, matrix, width) { .enter() .append("svg:svg") .attr("width", width) - .attr("height", width) + .attr("height", height) .attr("class", "dependencyWheel") .append("g") - .attr("transform", "translate(" + width / 2 + "," + width / 2 + ")"); + .attr( + "transform", + "translate(" + width / 2 + "," + height / 2 + ") scale(1.2)" + ); var arc = d3.svg .arc() @@ -206,8 +209,8 @@ function chordDiagram(recipient, elements, matrix, width) { .on("mousemove", move_tooltip); function move_tooltip(d) { - x = d3.event.pageX + 10; - y = d3.event.pageY + 10; + x = d3.event.layerX + 10; + y = d3.event.layerY + 10; $("#tooltip").css("left", x + "px"); $("#tooltip").css("top", y + "px"); diff --git a/pandora_console/include/javascript/datatablesFunction.js b/pandora_console/include/javascript/datatablesFunction.js new file mode 100644 index 0000000000..41f0bbf1e2 --- /dev/null +++ b/pandora_console/include/javascript/datatablesFunction.js @@ -0,0 +1,378 @@ +var dt = dt; +var config = config; + +var datacolumns = []; +var datacolumnsTemp = []; +dt.datacolumns.forEach(column => { + if (column === null) return; + if (typeof column !== "string") { + datacolumnsTemp = { data: column.text, className: column.class }; + datacolumns.push(datacolumnsTemp); + } else { + datacolumnsTemp = { data: column, className: "no-class" }; + datacolumns.push(datacolumnsTemp); + } +}); + +var paginationClass = "pandora_pagination"; +if (typeof dt.pagination_class !== "undefined") { + paginationClass = dt.pagination_class; +} + +var processing = ""; +if (typeof dt.processing === "undefined") { + processing = dt.processing; +} + +var ajaxReturn = ""; +var ajaxReturnFunction = ""; +if ( + typeof dt.ajax_return_operation !== "undefined" && + dt.ajax_return_operation !== "" && + typeof dt.ajax_return_operation_function !== "undefined" && + dt.ajax_return_operation_function !== "" +) { + ajaxReturn = dt.ajax_return_operation; + ajaxReturnFunction = dt.ajax_return_operation_function; +} + +var serverSide = true; +if (typeof dt.data_element !== "undefined") { + serverSide = false; +} + +var paging = true; +if (typeof dt.paging !== "undefined") { + paging = dt.paging; +} + +var pageLength = parseInt(dt.default_pagination); + +var searching = false; +if (typeof dt.searching !== "undefined" && dt.searching === true) { + searching = dt.searching; +} + +var dom = "plfrtiB"; +if (typeof dt.dom_elements !== "undefined") { + dom = dt.dom_elements; +} + +var lengthMenu = [ + [pageLength, 5, 10, 20, 100, 200, 500, 1000, -1], + [pageLength, 5, 10, 20, 100, 200, 500, 1000, "All"] +]; +if (typeof dt.pagination_options !== "undefined") { + lengthMenu = dt.pagination_options; +} + +var ordering = true; +if (typeof dt.ordering !== "undefined" && dt.ordering === false) { + ordering = dt.ordering; +} + +var order = [[0, "asc"]]; +if (typeof dt.order !== "undefined") { + order = [[dt.order.order, dt.order.direction]]; +} + +var zeroRecords = ""; +if (typeof dt.zeroRecords !== "undefined") { + zeroRecords = `${dt.zeroRecords}`; +} + +var emptyTable = ""; +if (typeof dt.emptyTable !== "undefined") { + emptyTable = `${dt.emptyTable}`; +} + +var no_sortable_columns = []; +if (typeof dt.no_sortable_columns !== "undefined") { + no_sortable_columns = Object.values(dt.no_sortable_columns); +} + +var columnDefs = []; +if (typeof dt.columnDefs === "undefined") { + columnDefs = [ + { className: "no-class", targets: "_all" }, + { bSortable: false, targets: no_sortable_columns } + ]; +} else { + columnDefs = dt.columnDefs; +} + +var csvClassName = "csv-button"; +if (dt.mini_csv === true) { + csvClassName = "mini-csv-button"; +} + +var csvFieldSeparator = ";"; +if (typeof dt.csv_field_separator !== "undefined") { + csvFieldSeparator = dt.csv_field_separator; +} + +var csvHeader = true; +if (dt.csv_header === false) { + csvHeader = false; +} + +var csvExcludeLast = ""; +if (dt.csv_exclude_latest === true) { + csvExcludeLast = "th:not(:last-child)"; +} + +var ajaxData = ""; +if (typeof dt.ajax_data !== "undefined") { + ajaxData = dt.ajax_data; +} + +$(document).ready(function() { + function checkPages() { + if (dt_table.page.info().pages > 1) { + $( + "div.pagination-child-div > .dataTables_paginate.paging_simple_numbers" + ).show(); + $(`#${dt.id}_paginate`).show(); + } else { + $( + "div.pagination-child-div > .dataTables_paginate.paging_simple_numbers" + ).hide(); + $(`#${dt.id}_paginate`).hide(); + } + } + + function moveElementsToActionButtons() { + $(".action_buttons_right_content").html( + '
' + ); + $(".pagination-child-div").append( + $(`#${dt.id}_wrapper > .dataTables_paginate.paging_simple_numbers`).attr( + "style", + "margin-right: 10px;" + ) + ); + $(".pagination-child-div").append( + $(`#${dt.id}_wrapper > .dataTables_length`) + ); + $(".pagination-child-div").append($(`#${dt.id}_wrapper > .dt-buttons`)); + $(".pagination-child-div").append( + $(`#${dt.id}_wrapper > .dataTables_filter`) + ); + } + + $.fn.dataTable.ext.errMode = "none"; + $.fn.dataTable.ext.classes.sPageButton = paginationClass; + + if (dt.mini_pagination === true) { + $.fn.dataTable.ext.classes.sPageButton = `${paginationClass} mini-pandora-pagination`; + } + + var settings_datatable = { + processing: true, + responsive: true, + serverSide, + paging, + pageLength, + searching, + dom, + lengthMenu, + ordering, + order, + columns: eval(datacolumns), + columnDefs, + language: { + url: dt.language, + processing, + zeroRecords, + emptyTable + }, + buttons: + dt.csv == 1 + ? [ + { + extend: "csv", + className: csvClassName, + text: dt.csvTextInfo, + titleAttr: dt.csvTextInfo, + title: dt.csvFileTitle, + fieldSeparator: csvFieldSeparator, + header: csvHeader, + action: function(e, dt, node, config) { + blockResubmit(node); + // Call the default csvHtml5 action method to create the CSV file + $.fn.dataTable.ext.buttons.csvHtml5.action.call( + this, + e, + dt, + node, + config + ); + }, + exportOptions: { + modifier: { + // DataTables core + order: "current", + page: "All", + search: "applied" + }, + columns: csvExcludeLast + } + } + ] + : [], + initComplete: function(settings, json) { + moveElementsToActionButtons(); + + checkPages(); + + $(`div#${dt.id}-spinner`).hide(); + }, + drawCallback: function(settings) { + if ($(`#${dt.id} tr td`).length == 1) { + $(`.datatable-msg-info-${dt.id}`) + .removeClass("invisible_important") + .show(); + $(`table#${dt.id}`).hide(); + $("div.pagination-child-div").hide(); + $("div.dataTables_info").hide(); + $(`#${dt.id}_wrapper`).hide(); + $(`.action_buttons_right_content .pagination-child-div`).hide(); + } else { + $(`.datatable-msg-info-${dt.id}`).hide(); + $(`table#${dt.id}`).show(); + $("div.pagination-child-div").show(); + $("div.dataTables_info").show(); + $(`#${dt.id}_wrapper`).show(); + + if (typeof dt.drawCallback !== "undefined") { + eval(dt.drawCallback); + } + } + + $(`div#${dt.id}-spinner`).hide(); + + checkPages(); + } + }; + + var ajaxOrData = {}; + if (typeof dt.data_element == "undefined") { + ajaxOrData = { + ajax: { + url: dt.ajax_url_full, + type: "POST", + dataSrc: function(json) { + if ($(`#${dt.form_id}_search_bt`) != undefined) { + $(`#${dt.form_id}_loading`).remove(); + } + + if (json.error) { + console.error(json.error); + $(`#error-${dt.id}`).html(json.error); + $(`#error-${dt.id}`) + .dialog({ + title: "Filter failed", + width: 630, + resizable: true, + draggable: true, + modal: false, + closeOnEscape: true, + buttons: { + Ok: function() { + $(this).dialog("close"); + } + } + }) + .parent() + .addClass("ui-state-error"); + } else { + if (json.ajaxReturn !== "undefined") { + eval(`${ajaxReturnFunction}(${json.ajaxReturn})`); + } + + if (typeof dt.ajax_postprocess !== "undefined") { + if (json.data) { + json.data.forEach(function(item) { + eval(dt.ajax_postprocess); + }); + } else { + json.data = {}; + } + } + + return json.data; + } + }, + data: function(data) { + $(`div#${dt.id}-spinner`).show(); + if ($(`#button-${dt.form_id}_search_bt`) != undefined) { + var loading = ``; + $(`#button-${dt.form_id}_search_bt`) + .parent() + .append(loading); + } + + var inputs = $(`#${dt.form_id} :input`); + + var values = {}; + inputs.each(function() { + values[this.name] = $(this).val(); + }); + + $.extend(data, ajaxData); + + $.extend(data, { + filter: values, + page: dt.ajax_url + }); + + return data; + } + } + }; + } else { + ajaxOrData = { data: dt.data_element }; + } + + $.extend(settings_datatable, ajaxOrData); + var dt_table = $(`#${dt.table_id}`).DataTable(settings_datatable); + + $(`#button-${dt.form_id}_search_bt`).click(function() { + dt_table.draw().page(0); + }); + + if (typeof dt.caption !== "undefined" && dt.caption !== "") { + $(`#${dt.table_id}`).append(`${dt.caption}`); + $(".datatables_thead_tr").css("height", 0); + } + + $(function() { + $(document).on("init.dt", function(ev, settings) { + if (dt.mini_search === true) { + $(`#${dt.id}_filter > label > input`).addClass("mini-search-input"); + } + + $("div.dataTables_length").show(); + $("div.dataTables_filter").show(); + $("div.dt-buttons").show(); + + if (dt_table.page.info().pages === 0) { + $(`.action_buttons_right_content .pagination-child-div`).hide(); + } + + if (dt_table.page.info().pages === 1) { + $(`div.pagination-child-div > #${dt.table_id}_paginate`).hide(); + } else { + $(`div.pagination-child-div > #${dt.table_id}_paginate`).show(); + } + }); + }); +}); + +$(function() { + $(document).on("preInit.dt", function(ev, settings) { + $(`#${dt.id}_wrapper div.dataTables_length`).hide(); + $(`#${dt.id}_wrapper div.dataTables_filter`).hide(); + $(`#${dt.id}_wrapper div.dt-buttons`).hide(); + }); +}); diff --git a/pandora_console/include/javascript/extensions_discovery.js b/pandora_console/include/javascript/extensions_discovery.js new file mode 100644 index 0000000000..a2cb6c85d0 --- /dev/null +++ b/pandora_console/include/javascript/extensions_discovery.js @@ -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(); + } +} diff --git a/pandora_console/include/javascript/i18n/dataTables.en.json b/pandora_console/include/javascript/i18n/dataTables.en.json index 9ccd76c4ad..d80bbe6e75 100644 --- a/pandora_console/include/javascript/i18n/dataTables.en.json +++ b/pandora_console/include/javascript/i18n/dataTables.en.json @@ -6,7 +6,6 @@ "infoThousands": ",", "lengthMenu": "Show _MENU_ entries", "loadingRecords": "Loading...", - "processing": "Processing...", "search": "Search:", "zeroRecords": "No matching records found", "thousands": ",", diff --git a/pandora_console/include/javascript/manage_extensions.js b/pandora_console/include/javascript/manage_extensions.js new file mode 100644 index 0000000000..e5c98c6a58 --- /dev/null +++ b/pandora_console/include/javascript/manage_extensions.js @@ -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; + } + }); + } + }); + }); +}); diff --git a/pandora_console/include/lib/Dashboard/Widget.php b/pandora_console/include/lib/Dashboard/Widget.php index b9e9971507..14712eee27 100644 --- a/pandora_console/include/lib/Dashboard/Widget.php +++ b/pandora_console/include/lib/Dashboard/Widget.php @@ -416,6 +416,10 @@ class Widget $className .= '\OsQuickReportWidget'; break; + case 'netflow': + $className .= '\Netflow'; + break; + case 'GroupedMeterGraphs': case 'ColorModuleTabs': case 'BlockHistogram': diff --git a/pandora_console/include/lib/Dashboard/Widgets/BasicChart.php b/pandora_console/include/lib/Dashboard/Widgets/BasicChart.php index ff5d22a539..85665e7e4c 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/BasicChart.php +++ b/pandora_console/include/lib/Dashboard/Widgets/BasicChart.php @@ -297,6 +297,14 @@ class BasicChart extends Widget $values['label'] = $decoder['label']; } + if (isset($decoder['type_graph']) === true) { + $values['type_graph'] = $decoder['type_graph']; + } + + if (isset($decoder['line_width']) === true) { + $values['line_width'] = $decoder['line_width']; + } + return $values; } @@ -477,6 +485,22 @@ class BasicChart extends Widget ], ]; + $types_graph = [ + 'area' => __('Area'), + 'line' => __('Wire'), + ]; + + $inputs['inputs']['row1'][] = [ + 'label' => __('Type graph'), + 'arguments' => [ + 'type' => 'select', + 'fields' => $types_graph, + 'name' => 'type_graph', + 'selected' => $values['type_graph'], + 'return' => true, + ], + ]; + $inputs['inputs']['row2'][] = [ 'label' => __('Show Value'), 'arguments' => [ @@ -520,6 +544,18 @@ class BasicChart extends Widget ], ]; + $inputs['inputs']['row2'][] = [ + 'label' => __('Graph line size'), + 'arguments' => [ + 'name' => 'line_width', + 'type' => 'number', + 'value' => (empty($values['line_width']) === true) ? 3 : $values['line_width'], + 'return' => true, + 'min' => 2, + 'max' => 10, + ], + ]; + return $inputs; } @@ -546,6 +582,8 @@ class BasicChart extends Widget $values['colorChart'] = \get_parameter('colorChart'); $values['formatData'] = \get_parameter_switch('formatData'); $values['label'] = \get_parameter('label'); + $values['type_graph'] = \get_parameter('type_graph'); + $values['line_width'] = \get_parameter('line_width'); return $values; } @@ -606,6 +644,8 @@ class BasicChart extends Widget 'title' => $module_name, 'unit' => $units_name, 'only_image' => false, + 'type_graph' => $this->values['type_graph'], + 'line_width' => (empty($this->values['line_width']) === true) ? 3 : $this->values['line_width'], 'menu' => false, 'vconsole' => true, 'return_img_base_64' => false, diff --git a/pandora_console/include/lib/Dashboard/Widgets/DataMatrix.php b/pandora_console/include/lib/Dashboard/Widgets/DataMatrix.php index b00c3ae421..10ddd2bc9c 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/DataMatrix.php +++ b/pandora_console/include/lib/Dashboard/Widgets/DataMatrix.php @@ -520,7 +520,7 @@ class DataMatrix extends Widget [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'include/ajax/module', diff --git a/pandora_console/include/lib/Dashboard/Widgets/ModulesByStatus.php b/pandora_console/include/lib/Dashboard/Widgets/ModulesByStatus.php index 86a50eefef..351d78ffec 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/ModulesByStatus.php +++ b/pandora_console/include/lib/Dashboard/Widgets/ModulesByStatus.php @@ -438,7 +438,7 @@ class ModulesByStatus extends Widget [ 'id' => $tableId, 'class' => 'info_table align-left-important', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'include/ajax/module', diff --git a/pandora_console/include/lib/Dashboard/Widgets/netflow.php b/pandora_console/include/lib/Dashboard/Widgets/netflow.php new file mode 100644 index 0000000000..be603e452b --- /dev/null +++ b/pandora_console/include/lib/Dashboard/Widgets/netflow.php @@ -0,0 +1,465 @@ +width = $width; + + // Height. + $this->height = $height; + + // Grid Width. + $this->gridWidth = $gridWidth; + + // Options. + $this->values = $this->getOptionsWidget(); + + // Positions. + $this->position = $this->getPositionWidget(); + + // Page. + $this->page = basename(__FILE__); + + // ClassName. + $class = new \ReflectionClass($this); + $this->className = $class->getShortName(); + + // Title. + $this->title = __('Netflow'); + + // Name. + if (empty($this->name) === true) { + $this->name = 'netflow'; + } + } + + + /** + * Generates inputs for form (specific). + * + * @return array Of inputs. + * + * @throws Exception On error. + */ + public function getFormInputs(): array + { + $values = $this->values; + + // Retrieve global - common inputs. + $inputs = parent::getFormInputs(); + + // Default values. + if (isset($values['quantity']) === false) { + $values['quantity'] = 5; + } + + // Default values. + if (isset($values['period']) === false) { + $values['period'] = SECONDS_1WEEK; + } + + // Default values. + if (isset($values['max_values']) === false) { + $values['max_values'] = 10; + } + + // Period. + $inputs[] = [ + 'label' => __('Interval'), + 'arguments' => [ + 'name' => 'period', + 'type' => 'interval', + 'value' => $values['period'], + 'nothing' => __('None'), + 'nothing_value' => 0, + 'style_icon' => 'flex-grow: 0', + ], + ]; + $chart_types = netflow_get_chart_types(); + $chart_types['usage_map'] = __('Usage map'); + $inputs[] = [ + 'label' => __('Type graph'), + 'arguments' => [ + 'name' => 'chart_type', + 'type' => 'select', + 'fields' => $chart_types, + 'selected' => $values['chart_type'], + ], + ]; + + $aggregate_list = [ + 'srcip' => __('Src Ip Address'), + 'dstip' => __('Dst Ip Address'), + 'srcport' => __('Src Port'), + 'dstport' => __('Dst Port'), + ]; + $inputs[] = [ + 'label' => __('Aggregated by'), + 'id' => 'aggregated', + 'arguments' => [ + 'name' => 'aggregate', + 'type' => 'select', + 'fields' => $aggregate_list, + 'selected' => $values['aggregate'], + ], + ]; + + $inputs[] = [ + 'label' => __('Data to show'), + 'id' => 'data_to_show', + 'arguments' => [ + 'name' => 'action', + 'type' => 'select', + 'fields' => network_get_report_actions(), + 'selected' => $values['action'], + ], + ]; + + $max_values = [ + '2' => '2', + '5' => '5', + '10' => '10', + '15' => '15', + '20' => '20', + '25' => '25', + '50' => '50', + ]; + + $inputs[] = [ + 'label' => __('Max values'), + 'arguments' => [ + 'name' => 'max_values', + 'type' => 'select', + 'fields' => $max_values, + 'selected' => $values['max_values'], + ], + ]; + + return $inputs; + } + + + /** + * Get Post for widget. + * + * @return array + */ + public function getPost():array + { + // Retrieve global - common inputs. + $values = parent::getPost(); + + $values['period'] = \get_parameter('period', 0); + $values['chart_type'] = \get_parameter('chart_type', ''); + $values['aggregate'] = \get_parameter('aggregate'); + $values['max_values'] = \get_parameter('max_values', 10); + $values['action'] = \get_parameter('action', 'srcip'); + + return $values; + } + + + /** + * Draw widget. + * + * @return string + */ + public function load() + { + ui_require_css_file('netflow_widget', 'include/styles/', true); + global $config; + + $output = ''; + + $size = parent::getSize(); + + $start_date = (time() - $this->values['period']); + $end_date = time(); + if ($this->values['chart_type'] === 'usage_map') { + $map_data = netflow_build_map_data( + $start_date, + $end_date, + $this->values['max_values'], + ($this->values['action'] === 'talkers') ? 'srcip' : 'dstip' + ); + $has_data = !empty($map_data['nodes']); + + if ($has_data === true) { + $map_manager = new \NetworkMap($map_data); + $map_manager->printMap(); + } else { + ui_print_info_message(__('No data to show')); + } + } else { + $netflowContainerClass = ($this->values['chart_type'] === 'netflow_data' || $this->values['chart_type'] === 'netflow_summary' || $this->values['chart_type'] === 'netflow_top_N') ? '' : 'white_box'; + $filter = [ + 'aggregate' => $this->values['aggregate'], + 'netflow_monitoring_interval' => 300, + ]; + + $output .= html_print_input_hidden( + 'selected_style_theme', + $config['style'], + true + ); + $style = 'width:100%; height: 100%; border: none;'; + if ($this->values['chart_type'] !== 'netflow_area') { + $style .= ' width: 95%;'; + } + + if ($size['width'] > $size['height']) { + $size['width'] = $size['height']; + } + + // Draw the netflow chart. + $output .= html_print_div( + [ + 'class' => $netflowContainerClass, + 'style' => $style, + 'content' => netflow_draw_item( + $start_date, + $end_date, + 12, + $this->values['chart_type'], + $filter, + $this->values['max_values'], + '', + 'HTML', + 0, + ($size['width'] - 50), + ($size['height'] - 20), + ), + ], + true + ); + } + + return $output; + + } + + + /** + * Return aux javascript code for forms. + * + * @return string + */ + public function getFormJS() + { + return ' + $(document).ready(function(){ + //Limit 1 week + $("#period_select option").each(function(key, element){ + if(element.value > 604800){ + $(element).remove(); + } + }) + $("#period_manual option").each(function(key, element){ + if(element.value > 604800){ + $(element).remove(); + } + }); + $("#period_manual input").on("change", function(e){ + if($("#hidden-period").val() > 604800) { + $(this).val(1); + $("#hidden-period").val(604800); + $("#period_manual select option").removeAttr("selected"); + setTimeout(() => { + $("#period_default select option[value=\'604800\']").attr("selected", "selected"); + $("#period_manual select option[value=\'604800\']").attr("selected", "selected"); + $("#period_manual select").val(604800); + }, 500); + } + }); + if($("#chart_type").val() === "usage_map") { + $("#data_to_show").show(); + $("#aggregated").hide(); + } else { + $("#data_to_show").hide(); + $("#aggregated").show(); + } + $("#chart_type").on("change", function(e){ + if(this.value === "usage_map") { + $("#data_to_show").show(); + $("#aggregated").hide(); + } else { + $("#data_to_show").hide(); + $("#aggregated").show(); + } + }); + }); + '; + } + + + /** + * Get description. + * + * @return string. + */ + public static function getDescription() + { + return __('Netflow'); + } + + + /** + * Get Name. + * + * @return string. + */ + public static function getName() + { + return 'netflow'; + } + + + /** + * Get size Modal Configuration. + * + * @return array + */ + public function getSizeModalConfiguration(): array + { + $size = [ + 'width' => 400, + 'height' => 530, + ]; + + return $size; + } + + +} diff --git a/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php b/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php index 7d00c43715..b026ffcd9e 100644 --- a/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php +++ b/pandora_console/include/lib/Dashboard/Widgets/system_group_status.php @@ -395,7 +395,9 @@ class SystemGroupStatusWidget extends Widget $user_groups = users_get_groups(false, 'AR', $return_all_group); $selected_groups = explode(',', $this->values['groupId'][0]); + $all_group_selected = false; if (in_array(0, $selected_groups) === true) { + $all_group_selected = true; $selected_groups = []; foreach (groups_get_all() as $key => $name_group) { $selected_groups[] = groups_get_id($name_group); @@ -480,7 +482,12 @@ class SystemGroupStatusWidget extends Widget } } - $this->values['groupId'] = $selected_groups; + if ($all_group_selected === true && $this->values['groupRecursion'] === true) { + $this->values['groupId'] = array_keys($result_groups); + } else { + $this->values['groupId'] = $selected_groups; + } + $this->values['status'] = explode(',', $this->values['status'][0]); $style = 'font-size: 1.5em; font-weight: bolder;text-align: center;'; diff --git a/pandora_console/include/streams.php b/pandora_console/include/streams.php index 9097750bf7..72f62ecce8 100644 --- a/pandora_console/include/streams.php +++ b/pandora_console/include/streams.php @@ -59,6 +59,7 @@ class StreamReader { class StringReader { var $_pos; var $_str; + var $is_overloaded; function __construct($str='') { $this->_str = $str; diff --git a/pandora_console/include/styles/discovery.css b/pandora_console/include/styles/discovery.css index 4bb7b200c6..2e6967f19a 100644 --- a/pandora_console/include/styles/discovery.css +++ b/pandora_console/include/styles/discovery.css @@ -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 { diff --git a/pandora_console/include/styles/form.css b/pandora_console/include/styles/form.css index fd7e496aac..a0e5957358 100644 --- a/pandora_console/include/styles/form.css +++ b/pandora_console/include/styles/form.css @@ -365,3 +365,7 @@ form#modal_form_feedback > ul > li > textarea { form#modal_form_feedback > ul > li:not(:first-child) > label { margin-top: 20px !important; } + +table.dataTable { + box-sizing: border-box !important; +} diff --git a/pandora_console/include/styles/login.css b/pandora_console/include/styles/login.css index 4314296d15..30d29c584c 100644 --- a/pandora_console/include/styles/login.css +++ b/pandora_console/include/styles/login.css @@ -351,6 +351,7 @@ span.span1 { font-family: "lato-bolder"; color: #fff; margin-right: 30px; + text-shadow: 2px 2px #000; } span.span2 { @@ -361,6 +362,7 @@ span.span2 { font-family: "lato-bolder"; color: #fff; margin-right: 30px; + text-shadow: 2px 2px #000; } div.img_banner_login img { diff --git a/pandora_console/include/styles/netflow_widget.css b/pandora_console/include/styles/netflow_widget.css new file mode 100644 index 0000000000..c7be7fe90d --- /dev/null +++ b/pandora_console/include/styles/netflow_widget.css @@ -0,0 +1,13 @@ +.menu_graph { + display: none; +} +.parent_graph { + width: 97% !important; +} +#image_hide_show_labels { + display: none !important; +} + +.select2-search--dropdown .select2-search__field { + padding: 0px !important; +} diff --git a/pandora_console/include/styles/pandora.css b/pandora_console/include/styles/pandora.css index e0ca7fc68f..018cd7a0a6 100644 --- a/pandora_console/include/styles/pandora.css +++ b/pandora_console/include/styles/pandora.css @@ -4210,13 +4210,6 @@ div.simple_value > a > span.text p { } .modalokbutton { - transition-property: background-color, color; - transition-duration: 1s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color, color; - -webkit-transition-duration: 1s; - -o-transition-property: background-color, color; - -o-transition-duration: 1s; cursor: pointer; text-align: center; margin-right: 45px; @@ -4227,44 +4220,24 @@ div.simple_value > a > span.text p { border-radius: 3px; width: 90px; height: 30px; - background-color: white; - border: 1px solid #82b92e; + background-color: var(--primary-color); + border: 1px solid var(--primary-color); + border-radius: 6px; } .modalokbuttontext { - transition-property: background-color, color; - transition-duration: 1s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color, color; - -webkit-transition-duration: 1s; - -o-transition-property: background-color, color; - -o-transition-duration: 1s; - color: #82b92e; + color: #fff; font-size: 10pt; position: relative; top: 6px; } .modalokbutton:hover { - transition-property: background-color, color; - transition-duration: 1s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color, color; - -webkit-transition-duration: 1s; - -o-transition-property: background-color, color; - -o-transition-duration: 1s; - background-color: #82b92e; + background-color: var(--primary-color); } .modalokbutton:hover .modalokbuttontext { - transition-property: background-color, color; - transition-duration: 1s; - transition-timing-function: ease-out; - -webkit-transition-property: background-color, color; - -webkit-transition-duration: 1s; - -o-transition-property: background-color, color; - -o-transition-duration: 1s; - color: white; + color: #fff; } .modaldeletebutton { @@ -7623,6 +7596,10 @@ div.graph div.legend table { padding-bottom: 10px !important; } +.pdd_b_15px_important { + padding-bottom: 15px !important; +} + .pdd_b_20px { padding-bottom: 20px; } @@ -7701,6 +7678,10 @@ div.graph div.legend table { padding-top: 15px; } +.pdd_t_15px_important { + padding-top: 15px !important; +} + .pdd_t_20px { padding-top: 20px; } @@ -9037,8 +9018,7 @@ div.graph div.legend table { } .app_mssg { - position: absolute; - bottom: 1em; + margin: 1em; clear: both; color: #888; } @@ -11666,14 +11646,14 @@ p.trademark-copyright { } .show-hide-pass { - position: relative; - right: 40px; + position: absolute; + right: 9px; top: 4px; border: 0; outline: none; margin: 0; height: 30px; - width: 30px; + width: 40px; cursor: pointer; display: inline-block; } @@ -11949,7 +11929,7 @@ span.help_icon_15px > img { /* ==== Spinner ==== */ .spinner-fixed { position: absolute; - left: 40%; + left: 45%; top: 40%; z-index: 1; width: 100px; @@ -11959,6 +11939,7 @@ span.help_icon_15px > img { animation: animate 1.2s linear infinite; margin: auto; margin-bottom: 40px; + text-align: initial; } .spinner-fixed span { position: absolute; @@ -12341,3 +12322,10 @@ tr[id^="network_component-plugin-wmi-fields-dynamicMacroRow-"] input, tr[id^="network_component-plugin-snmp-fields-dynamicMacroRow-"] input { width: 100% !important; } + +.start-end-date-log-viewer { + display: flex; + flex-direction: row !important; + flex-wrap: nowrap; + justify-content: flex-start !important; +} diff --git a/pandora_console/include/styles/tables.css b/pandora_console/include/styles/tables.css index 562ffc3c80..6974aed9e8 100644 --- a/pandora_console/include/styles/tables.css +++ b/pandora_console/include/styles/tables.css @@ -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; } @@ -381,15 +383,35 @@ a.pandora_pagination.current:hover { cursor: pointer; } +.dt-button.buttons-csv.buttons-html5.mini-csv-button { + background-image: url(../../images/file-csv.svg); + background-position: 4px center; + height: 26px; + width: 31px; + margin-left: 10px; + box-shadow: 0px 0px 0px #00000000; + border: 0px; + border-radius: 0px; +} + .dt-button.buttons-csv.buttons-html5:hover { color: #1d7873 !important; border: 2px solid #1d7873 !important; } +.dt-button.buttons-csv.buttons-html5.mini-csv-button:hover { + color: #00000000 !important; + border: 0px !important; +} + .dt-button.buttons-csv.buttons-html5:before { content: "csv"; } +.dt-button.buttons-csv.buttons-html5.mini-csv-button:before { + content: ""; +} + .dt-button.buttons-csv.buttons-html5 span { font-size: 0; } diff --git a/pandora_console/index.php b/pandora_console/index.php index 75c00af9b1..b3566e3589 100755 --- a/pandora_console/index.php +++ b/pandora_console/index.php @@ -292,7 +292,7 @@ enterprise_include_once('include/auth/saml.php'); if (isset($config['id_user']) === false) { // Clear error messages. unset($_COOKIE['errormsg']); - setcookie('errormsg', null, -1); + setcookie('errormsg', '', -1); if (isset($_GET['login']) === true) { include_once 'include/functions_db.php'; diff --git a/pandora_console/install.php b/pandora_console/install.php index e5ce174350..0114a4f222 100644 --- a/pandora_console/install.php +++ b/pandora_console/install.php @@ -131,7 +131,7 @@
'ui-icon-menu-group ui-widget-icon-floatbeginning ui-icon-menu-square', ]; - if ((bool) $system->getConfig('legacy_vc', false) === false) { - // Show Visual consoles only if new system is enabled. - $items['visualmaps'] = [ - 'name' => __('Visual consoles'), - 'filename' => 'visualmaps.php', - 'menu_item' => true, - 'icon' => 'ui-icon-menu-visual_console ui-widget-icon-floatbeginning ui-icon-menu-square', - ]; - } + // Show Visual consoles only if new system is enabled. + $items['visualmaps'] = [ + 'name' => __('Visual consoles'), + 'filename' => 'visualmaps.php', + 'menu_item' => true, + 'icon' => 'ui-icon-menu-visual_console ui-widget-icon-floatbeginning ui-icon-menu-square', + ]; $items['alerts'] = [ 'name' => __('Alerts'), diff --git a/pandora_console/operation/agentes/alerts_status.php b/pandora_console/operation/agentes/alerts_status.php index 4db865990f..07974af99e 100755 --- a/pandora_console/operation/agentes/alerts_status.php +++ b/pandora_console/operation/agentes/alerts_status.php @@ -258,7 +258,8 @@ if ((bool) check_acl($config['id_user'], $id_group, 'LW') === true || (bool) che ); } - if ($print_agent === true) { + /* + if ($print_agent === true) { array_push( $column_names, ['text' => 'Agent'] @@ -268,11 +269,12 @@ if ((bool) check_acl($config['id_user'], $id_group, 'LW') === true || (bool) che $columns, ['agent_name'] ); - } + }*/ } array_push( $column_names, + ['text' => 'Agent'], ['text' => 'Module'], ['text' => 'Template'], [ @@ -286,6 +288,7 @@ array_push( $columns = array_merge( $columns, + ['agent_name'], ['agent_module_name'], ['template_name'], ['action'], @@ -359,7 +362,7 @@ if ($agent_view_page === true) { [ 'id' => 'alerts_status_datatable', 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'no_sortable_columns' => $no_sortable_columns, diff --git a/pandora_console/operation/agentes/pandora_networkmap.php b/pandora_console/operation/agentes/pandora_networkmap.php index 540cd8c173..be4837ea65 100644 --- a/pandora_console/operation/agentes/pandora_networkmap.php +++ b/pandora_console/operation/agentes/pandora_networkmap.php @@ -256,152 +256,165 @@ if ($new_networkmap || $save_networkmap) { $name = (string) get_parameter('name'); - // Default size values. - $width = $config['networkmap_max_width']; - $height = $config['networkmap_max_width']; - - $method = (string) get_parameter('method', 'fdp'); - - $recon_task_id = (int) get_parameter( - 'recon_task_id', - 0 + $exist = db_get_row_filter( + 'tmap', + [ + 'name' => $name, + 'id_group_map' => $id_group_map, + ], ); - $ip_mask = get_parameter( - 'ip_mask', - '' - ); - $source = (string) get_parameter('source', 'group'); - $dont_show_subgroups = (int) get_parameter_checkbox( - 'dont_show_subgroups', - 0 - ); - $node_radius = (int) get_parameter('node_radius', 40); - $description = get_parameter('description', ''); + hd('Entraaaa', true); + hd($exist, true); + if ($exist !== false) { + $result_txt = ui_print_error_message(__('Another network map already exists with this name and group.')); + } else { + // Default size values. + $width = $config['networkmap_max_width']; + $height = $config['networkmap_max_width']; - $offset_x = get_parameter('pos_x', 0); - $offset_y = get_parameter('pos_y', 0); - $scale_z = get_parameter('scale_z', 0.5); + $method = (string) get_parameter('method', 'fdp'); - $node_sep = get_parameter('node_sep', '0.25'); - $rank_sep = get_parameter('rank_sep', ($method === 'twopi') ? '1.0' : '0.5'); - - $mindist = get_parameter('mindist', '1.0'); - $kval = get_parameter('kval', '0.3'); - - $refresh_time = get_parameter('refresh_time', '300'); - - $values = []; - $values['name'] = $name; - $values['id_group'] = implode(',', $id_group); - $values['source_period'] = 60; - $values['width'] = $width; - $values['height'] = $height; - $values['id_user'] = $config['id_user']; - $values['description'] = $description; - $values['id_group_map'] = $id_group_map; - $values['refresh_time'] = $refresh_time; - - switch ($method) { - case 'twopi': - $values['generation_method'] = LAYOUT_RADIAL; - break; - - case 'dot': - $values['generation_method'] = LAYOUT_FLAT; - break; - - case 'circo': - $values['generation_method'] = LAYOUT_CIRCULAR; - break; - - case 'neato': - $values['generation_method'] = LAYOUT_SPRING1; - break; - - case 'fdp': - $values['generation_method'] = LAYOUT_SPRING2; - break; - - case 'radial_dinamic': - $values['generation_method'] = LAYOUT_RADIAL_DYNAMIC; - break; - - default: - $values['generation_method'] = LAYOUT_RADIAL; - break; - } - - if ($source == 'group') { - $values['source'] = 0; - $values['source_data'] = implode(',', $id_group); - } else if ($source == 'recon_task') { - $values['source'] = 1; - $values['source_data'] = $recon_task_id; - } else if ($source == 'ip_mask') { - $values['source'] = 2; - $values['source_data'] = $ip_mask; - } - - if ($networkmap_write === false && $networkmap_manage === false) { - db_pandora_audit( - AUDIT_LOG_ACL_VIOLATION, - 'Trying to access networkmap' + $recon_task_id = (int) get_parameter( + 'recon_task_id', + 0 ); - include 'general/noaccess.php'; - return; - } - - $filter = []; - $filter['dont_show_subgroups'] = $dont_show_subgroups; - $filter['node_radius'] = $node_radius; - $filter['x_offs'] = $offset_x; - $filter['y_offs'] = $offset_y; - $filter['z_dash'] = $scale_z; - $filter['node_sep'] = $node_sep; - $filter['rank_sep'] = $rank_sep; - $filter['mindist'] = $mindist; - $filter['kval'] = $kval; - - $values['filter'] = json_encode($filter); - - $result = false; - if (!empty($name)) { - $result = db_process_sql_insert( - 'tmap', - $values + $ip_mask = get_parameter( + 'ip_mask', + '' ); - } + $source = (string) get_parameter('source', 'group'); + $dont_show_subgroups = (int) get_parameter_checkbox( + 'dont_show_subgroups', + 0 + ); + $node_radius = (int) get_parameter('node_radius', 40); + $description = get_parameter('description', ''); - $result_txt = ui_print_result_message( - $result, - __('Succesfully created'), - __('Could not be created'), - '', - true - ); + $offset_x = get_parameter('pos_x', 0); + $offset_y = get_parameter('pos_y', 0); + $scale_z = get_parameter('scale_z', 0.5); - $id = $result; - define('_id_', $id); + $node_sep = get_parameter('node_sep', '0.25'); + $rank_sep = get_parameter('rank_sep', ($method === 'twopi') ? '1.0' : '0.5'); - if ($result !== false) { - $tab = 'view'; - if ($values['generation_method'] == LAYOUT_RADIAL_DYNAMIC) { - $tab = 'r_dinamic'; - define('_activeTab_', 'radial_dynamic'); - $url = 'index.php?sec=network&sec2=operation/agentes/networkmap.dinamic&activeTab=radial_dynamic'; - header( - 'Location: '.ui_get_full_url( - $url.'&id_networkmap='.$id - ) + $mindist = get_parameter('mindist', '1.0'); + $kval = get_parameter('kval', '0.3'); + + $refresh_time = get_parameter('refresh_time', '300'); + + $values = []; + $values['name'] = $name; + $values['id_group'] = implode(',', $id_group); + $values['source_period'] = 60; + $values['width'] = $width; + $values['height'] = $height; + $values['id_user'] = $config['id_user']; + $values['description'] = $description; + $values['id_group_map'] = $id_group_map; + $values['refresh_time'] = $refresh_time; + + switch ($method) { + case 'twopi': + $values['generation_method'] = LAYOUT_RADIAL; + break; + + case 'dot': + $values['generation_method'] = LAYOUT_FLAT; + break; + + case 'circo': + $values['generation_method'] = LAYOUT_CIRCULAR; + break; + + case 'neato': + $values['generation_method'] = LAYOUT_SPRING1; + break; + + case 'fdp': + $values['generation_method'] = LAYOUT_SPRING2; + break; + + case 'radial_dinamic': + $values['generation_method'] = LAYOUT_RADIAL_DYNAMIC; + break; + + default: + $values['generation_method'] = LAYOUT_RADIAL; + break; + } + + if ($source == 'group') { + $values['source'] = 0; + $values['source_data'] = implode(',', $id_group); + } else if ($source == 'recon_task') { + $values['source'] = 1; + $values['source_data'] = $recon_task_id; + } else if ($source == 'ip_mask') { + $values['source'] = 2; + $values['source_data'] = $ip_mask; + } + + if ($networkmap_write === false && $networkmap_manage === false) { + db_pandora_audit( + AUDIT_LOG_ACL_VIOLATION, + 'Trying to access networkmap' ); - } else { - $url = 'index.php?sec=network&sec2=operation/agentes/pandora_networkmap'; - header( - 'Location: '.ui_get_full_url( - $url.'&tab='.$tab.'&id_networkmap='.$id - ) + include 'general/noaccess.php'; + return; + } + + $filter = []; + $filter['dont_show_subgroups'] = $dont_show_subgroups; + $filter['node_radius'] = $node_radius; + $filter['x_offs'] = $offset_x; + $filter['y_offs'] = $offset_y; + $filter['z_dash'] = $scale_z; + $filter['node_sep'] = $node_sep; + $filter['rank_sep'] = $rank_sep; + $filter['mindist'] = $mindist; + $filter['kval'] = $kval; + + $values['filter'] = json_encode($filter); + + $result = false; + if (!empty($name)) { + $result = db_process_sql_insert( + 'tmap', + $values ); } + + $result_txt = ui_print_result_message( + $result, + __('Succesfully created'), + __('Could not be created'), + '', + true + ); + + $id = $result; + define('_id_', $id); + + if ($result !== false) { + $tab = 'view'; + if ($values['generation_method'] == LAYOUT_RADIAL_DYNAMIC) { + $tab = 'r_dinamic'; + define('_activeTab_', 'radial_dynamic'); + $url = 'index.php?sec=network&sec2=operation/agentes/networkmap.dinamic&activeTab=radial_dynamic'; + header( + 'Location: '.ui_get_full_url( + $url.'&id_networkmap='.$id + ) + ); + } else { + $url = 'index.php?sec=network&sec2=operation/agentes/pandora_networkmap'; + header( + 'Location: '.ui_get_full_url( + $url.'&tab='.$tab.'&id_networkmap='.$id + ) + ); + } + } } } } @@ -464,70 +477,81 @@ else if ($update_networkmap || $copy_networkmap || $delete) { } $name = (string) get_parameter('name', ''); - - $recon_task_id = (int) get_parameter( - 'recon_task_id', - 0 + $exist = db_get_row_filter( + 'tmap', + [ + 'name' => $name, + 'id_group_map' => $id_group_map, + ], ); - $source = (string) get_parameter('source', 'group'); - - $offset_x = get_parameter('pos_x', 0); - $offset_y = get_parameter('pos_y', 0); - $scale_z = get_parameter('scale_z', 0.5); - - $refresh_time = get_parameter('refresh_time', '300'); - - $values = []; - $values['name'] = $name; - $values['id_group'] = implode(',', $id_group); - $values['id_group_map'] = $id_group_map; - - $description = get_parameter('description', ''); - $values['description'] = $description; - - $values['refresh_time'] = $refresh_time; - - $dont_show_subgroups = (int) get_parameter('dont_show_subgroups', 0); - $node_radius = (int) get_parameter('node_radius', 40); - $row = db_get_row('tmap', 'id', $id); - $filter = json_decode($row['filter'], true); - $filter['dont_show_subgroups'] = $dont_show_subgroups; - $filter['node_radius'] = $node_radius; - $filter['x_offs'] = $offset_x; - $filter['y_offs'] = $offset_y; - $filter['z_dash'] = $scale_z; - - $values['filter'] = json_encode($filter); - - $result = false; - if (empty($name) === false) { - $result = db_process_sql_update( - 'tmap', - $values, - ['id' => $id] + if ($exist !== false) { + $result_txt = ui_print_error_message(__('Another network map already exists with this name and group.')); + } else { + $recon_task_id = (int) get_parameter( + 'recon_task_id', + 0 ); - ui_update_name_fav_element($id, 'Network_map', $name); - } - $result_txt = ui_print_result_message( - $result, - __('Succesfully updated'), - __('Could not be updated'), - '', - true - ); + $source = (string) get_parameter('source', 'group'); - if ($result) { - // If change the group, the map must be regenerated - if ($id_group != $id_group_old) { - networkmap_delete_nodes($id); - // Delete relations. - networkmap_delete_relations($id); + $offset_x = get_parameter('pos_x', 0); + $offset_y = get_parameter('pos_y', 0); + $scale_z = get_parameter('scale_z', 0.5); + + $refresh_time = get_parameter('refresh_time', '300'); + + $values = []; + $values['name'] = $name; + $values['id_group'] = implode(',', $id_group); + $values['id_group_map'] = $id_group_map; + + $description = get_parameter('description', ''); + $values['description'] = $description; + + $values['refresh_time'] = $refresh_time; + + $dont_show_subgroups = (int) get_parameter('dont_show_subgroups', 0); + $node_radius = (int) get_parameter('node_radius', 40); + $row = db_get_row('tmap', 'id', $id); + $filter = json_decode($row['filter'], true); + $filter['dont_show_subgroups'] = $dont_show_subgroups; + $filter['node_radius'] = $node_radius; + $filter['x_offs'] = $offset_x; + $filter['y_offs'] = $offset_y; + $filter['z_dash'] = $scale_z; + + $values['filter'] = json_encode($filter); + + $result = false; + if (empty($name) === false) { + $result = db_process_sql_update( + 'tmap', + $values, + ['id' => $id] + ); + ui_update_name_fav_element($id, 'Network_map', $name); } - $networkmap_write = $networkmap_write_new; - $networkmap_manage = $networkmap_manage_new; + $result_txt = ui_print_result_message( + $result, + __('Succesfully updated'), + __('Could not be updated'), + '', + true + ); + + if ($result) { + // If change the group, the map must be regenerated + if ($id_group != $id_group_old) { + networkmap_delete_nodes($id); + // Delete relations. + networkmap_delete_relations($id); + } + + $networkmap_write = $networkmap_write_new; + $networkmap_manage = $networkmap_manage_new; + } } } diff --git a/pandora_console/operation/events/events.php b/pandora_console/operation/events/events.php index caf2e70c76..0eb1bc152a 100644 --- a/pandora_console/operation/events/events.php +++ b/pandora_console/operation/events/events.php @@ -2540,7 +2540,7 @@ try { [ 'id' => $table_id, 'class' => 'info_table events', - 'style' => 'width: 99%;', + 'style' => 'width: 100%;', 'ajax_url' => 'operation/events/events', 'ajax_data' => [ 'get_events' => 1, diff --git a/pandora_console/operation/inventory/inventory.php b/pandora_console/operation/inventory/inventory.php index 63b302062c..536f470fe6 100755 --- a/pandora_console/operation/inventory/inventory.php +++ b/pandora_console/operation/inventory/inventory.php @@ -804,7 +804,7 @@ if ($inventory_module !== 'basic') { [ 'id' => $id_table, 'class' => 'info_table w100p', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columns, 'no_sortable_columns' => [], @@ -919,7 +919,7 @@ if ($inventory_module !== 'basic') { [ 'id' => $id_table, 'class' => 'info_table w100p', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columns, 'no_sortable_columns' => [], @@ -1083,7 +1083,7 @@ if ($inventory_module !== 'basic') { [ 'id' => $id_table, 'class' => 'info_table w100p', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columns, 'no_sortable_columns' => [], @@ -1173,7 +1173,7 @@ if ($inventory_module !== 'basic') { [ 'id' => $id_table, 'class' => 'info_table w100p', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columns, 'no_sortable_columns' => [], @@ -1188,6 +1188,8 @@ if ($inventory_module !== 'basic') { 'emptyTable' => __('No inventory found'), 'return' => true, 'no_sortable_columns' => [], + 'mini_search' => true, + 'mini_pagination' => true, ] ); @@ -1204,7 +1206,7 @@ if ($inventory_module !== 'basic') { [ 'id' => $id_table, 'class' => 'info_table w100p', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $columns, 'no_sortable_columns' => [], @@ -1233,7 +1235,7 @@ if ($inventory_module !== 'basic') { $agentes = []; $data = []; $class = 'info_table'; - $style = 'width: 99%'; + $style = 'width: 100%'; $ordering = true; $searching = false; diff --git a/pandora_console/operation/visual_console/public_console.php b/pandora_console/operation/visual_console/public_console.php index 0330f117c4..ae55cff765 100755 --- a/pandora_console/operation/visual_console/public_console.php +++ b/pandora_console/operation/visual_console/public_console.php @@ -15,13 +15,8 @@ // The session is configured and started inside the config process. require_once '../../include/config.php'; -$legacy = (bool) get_parameter('legacy', $config['legacy_vc']); if (is_metaconsole() === true) { $config['requirements_use_base_url'] = true; } -if ($legacy === false) { - include_once $config['homedir'].'/operation/visual_console/public_view.php'; -} else { - include_once $config['homedir'].'/operation/visual_console/legacy_public_view.php'; -} +require_once $config['homedir'].'/operation/visual_console/public_view.php'; diff --git a/pandora_console/operation/visual_console/render_view.php b/pandora_console/operation/visual_console/render_view.php index f1b1d70f91..33c52a62b9 100755 --- a/pandora_console/operation/visual_console/render_view.php +++ b/pandora_console/operation/visual_console/render_view.php @@ -13,9 +13,4 @@ // GNU General Public License for more details. global $config; -$legacy = (bool) get_parameter('legacy', $config['legacy_vc']); -if ($legacy === false) { - include_once $config['homedir'].'/operation/visual_console/view.php'; -} else { - include_once $config['homedir'].'/operation/visual_console/legacy_view.php'; -} +require_once $config['homedir'].'/operation/visual_console/view.php'; diff --git a/pandora_console/pandora_console.redhat.spec b/pandora_console/pandora_console.redhat.spec index 7d9a5bfc33..d60cfd3308 100644 --- a/pandora_console/pandora_console.redhat.spec +++ b/pandora_console/pandora_console.redhat.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.772 -%define release 230719 +%define release 230727 # User and Group under which Apache is running %define httpd_name httpd @@ -15,7 +15,7 @@ Name: %{name} Version: %{version} Release: %{release} License: GPL -Vendor: Artica ST +Vendor: Pandora FMS #Source0: %{name}-%{version}-%{revision}.tar.gz Source0: %{name}-%{version}.tar.gz URL: http://www.pandorafms.com diff --git a/pandora_console/pandora_console.rhel7.spec b/pandora_console/pandora_console.rhel7.spec index 7fca923011..ad0fa12ce0 100644 --- a/pandora_console/pandora_console.rhel7.spec +++ b/pandora_console/pandora_console.rhel7.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.772 -%define release 230719 +%define release 230727 # User and Group under which Apache is running %define httpd_name httpd @@ -15,7 +15,7 @@ Name: %{name} Version: %{version} Release: %{release} License: GPL -Vendor: Artica ST +Vendor: Pandora FMS #Source0: %{name}-%{version}-%{revision}.tar.gz Source0: %{name}-%{version}.tar.gz URL: http://www.pandorafms.com diff --git a/pandora_console/pandora_console.spec b/pandora_console/pandora_console.spec index c160592a94..1e62dd19a7 100644 --- a/pandora_console/pandora_console.spec +++ b/pandora_console/pandora_console.spec @@ -3,7 +3,7 @@ # %define name pandorafms_console %define version 7.0NG.772 -%define release 230719 +%define release 230727 %define httpd_name httpd # User and Group under which Apache is running %define httpd_name apache2 @@ -18,7 +18,7 @@ Name: %{name} Version: %{version} Release: %{release} License: GPL -Vendor: Artica ST +Vendor: Pandora FMS Source0: %{name}-%{version}.tar.gz URL: http://www.pandorafms.org Group: System/Monitoring diff --git a/pandora_console/pandora_websocket_engine b/pandora_console/pandora_websocket_engine index 6b87c75763..2d4536aae0 100755 --- a/pandora_console/pandora_websocket_engine +++ b/pandora_console/pandora_websocket_engine @@ -39,7 +39,7 @@ if [[ -z ${PANDORA_RB_PRODUCT_NAME} ]]; then PANDORA_RB_PRODUCT_NAME="Pandora FMS" fi if [[ -z ${PANDORA_RB_COPYRIGHT_NOTICE} ]]; then - PANDORA_RB_COPYRIGHT_NOTICE="Artica ST" + PANDORA_RB_COPYRIGHT_NOTICE="Pandora FMS" fi export PANDORA_RB_PRODUCT_NAME=$PANDORA_RB_PRODUCT_NAME diff --git a/pandora_console/pandoradb.sql b/pandora_console/pandoradb.sql index a0127937df..440199f901 100644 --- a/pandora_console/pandoradb.sql +++ b/pandora_console/pandoradb.sql @@ -844,6 +844,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) -- ---------------------------------------------------------------------- @@ -894,8 +905,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; -- ---------------------------------------------------------------------- @@ -3762,20 +3777,6 @@ CREATE TABLE IF NOT EXISTS `tagent_custom_fields_filter` ( PRIMARY KEY(`id`) ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; --- ----------------------------------------------------- --- Table `tnetwork_matrix` --- ----------------------------------------------------- -CREATE TABLE IF NOT EXISTS `tnetwork_matrix` ( - `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `source` VARCHAR(60) DEFAULT '', - `destination` VARCHAR(60) DEFAULT '', - `utimestamp` BIGINT DEFAULT 0, - `bytes` INT UNSIGNED DEFAULT 0, - `pkts` INT UNSIGNED DEFAULT 0, - PRIMARY KEY (`id`), - UNIQUE (`source`, `destination`, `utimestamp`) -) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4 ; - -- --------------------------------------------------------------------- -- Table `user_task` -- --------------------------------------------------------------------- @@ -4343,6 +4344,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` -- --------------------------------------------------------------------- @@ -4365,4 +4404,4 @@ CREATE TABLE IF NOT EXISTS `tnetwork_explorer_filter` ( `action` VARCHAR(45) NULL, `advanced_filter` TEXT NULL, PRIMARY KEY (`id`) - ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; \ No newline at end of file + ) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4; diff --git a/pandora_console/vendor/artica/phpchartjs/composer.json b/pandora_console/vendor/artica/phpchartjs/composer.json index 81cd50ecf5..39d63f4fd4 100644 --- a/pandora_console/vendor/artica/phpchartjs/composer.json +++ b/pandora_console/vendor/artica/phpchartjs/composer.json @@ -7,7 +7,7 @@ "php" ], "readme": "README.md", - "homepage": "https://artica.es/", + "homepage": "https://pandorafms.com/", "type": "package", "version": "v1.0.2", "license": "AGPL-3.0-or-later", diff --git a/pandora_console/vendor/composer/installed.json b/pandora_console/vendor/composer/installed.json index 1022a9f68b..3679134135 100644 --- a/pandora_console/vendor/composer/installed.json +++ b/pandora_console/vendor/composer/installed.json @@ -629,7 +629,7 @@ } ], "description": "PHP library for ChartJS", - "homepage": "https://artica.es/", + "homepage": "https://pandorafms.com/", "keywords": [ "chartjs", "graph", diff --git a/pandora_console/views/calendar/list.php b/pandora_console/views/calendar/list.php index 236f20460e..2a7c0721c9 100644 --- a/pandora_console/views/calendar/list.php +++ b/pandora_console/views/calendar/list.php @@ -105,7 +105,7 @@ try { [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $ajax_url, diff --git a/pandora_console/views/cluster/list.php b/pandora_console/views/cluster/list.php index f9afe627c1..39c00efd91 100644 --- a/pandora_console/views/cluster/list.php +++ b/pandora_console/views/cluster/list.php @@ -82,7 +82,7 @@ try { [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => $model->ajaxController, diff --git a/pandora_console/views/consoles/list.php b/pandora_console/views/consoles/list.php index 14131f4357..a35f0818cf 100644 --- a/pandora_console/views/consoles/list.php +++ b/pandora_console/views/consoles/list.php @@ -86,7 +86,7 @@ try { [ 'id' => $tableId, 'class' => 'info_table', - 'style' => 'width: 99%', + 'style' => 'width: 100%', 'columns' => $columns, 'column_names' => $column_names, 'ajax_url' => 'include/ajax/consoles.ajax', diff --git a/pandora_server/DEBIAN/control b/pandora_server/DEBIAN/control index 28d2381ed1..fb99535be3 100644 --- a/pandora_server/DEBIAN/control +++ b/pandora_server/DEBIAN/control @@ -1,10 +1,10 @@ package: pandorafms-server -Version: 7.0NG.772-230719 +Version: 7.0NG.772-230727 Architecture: all Priority: optional Section: admin Installed-Size: 640 -Maintainer: ÁRTICA ST +Maintainer: Pandora FMS Homepage: http://pandorafms.org/ Depends: perl (>= 5.8), libdbi-perl, libdbd-mysql-perl, libtime-format-perl, libnetaddr-ip-perl, libtime-format-perl, libxml-simple-perl, libxml-twig-perl, libhtml-parser-perl, snmp, snmpd, traceroute, nmap, sudo, libwww-perl, libsocket6-perl, libio-socket-inet6-perl, libio-socket-ssl-perl, snmp-mibs-downloader, libjson-perl, libnet-telnet-perl, libencode-locale-perl, libgeo-ip-perl Description: Pandora FMS is a monitoring system for big IT environments. It uses remote tests, or local agents to grab information. Pandora supports all standard OS (Linux, AIX, HP-UX, Solaris and Windows XP,2000/2003), and support multiple setups in HA enviroments. This is the server package. Server makes the remote checks and process information transfer by Pandora FMS agents to the server. diff --git a/pandora_server/DEBIAN/make_deb_package.sh b/pandora_server/DEBIAN/make_deb_package.sh index a7305b7a36..7181f2c079 100644 --- a/pandora_server/DEBIAN/make_deb_package.sh +++ b/pandora_server/DEBIAN/make_deb_package.sh @@ -14,7 +14,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -pandora_version="7.0NG.772-230719" +pandora_version="7.0NG.772-230727" package_cpan=0 package_pandora=1 diff --git a/pandora_server/Makefile.PL b/pandora_server/Makefile.PL index ac1c613f3b..107bd69c3f 100644 --- a/pandora_server/Makefile.PL +++ b/pandora_server/Makefile.PL @@ -17,7 +17,7 @@ WriteMakefile( NAME => 'PandoraFMS', VERSION_FROM => 'lib/PandoraFMS/Config.pm', - AUTHOR => 'Artica ST ', + AUTHOR => 'Pandora FMS ', PREREQ_PM => { NetAddr::IP => 0, DBI => 0, diff --git a/pandora_server/lib/PandoraFMS/Config.pm b/pandora_server/lib/PandoraFMS/Config.pm index 095b0a1b1d..d69e7584a2 100644 --- a/pandora_server/lib/PandoraFMS/Config.pm +++ b/pandora_server/lib/PandoraFMS/Config.pm @@ -46,7 +46,7 @@ our @EXPORT = qw( # version: Defines actual version of Pandora Server for this module only my $pandora_version = "7.0NG.772"; -my $pandora_build = "230719"; +my $pandora_build = "230727"; our $VERSION = $pandora_version." ".$pandora_build; # Setup hash @@ -1535,7 +1535,7 @@ sub pandora_get_initial_product_name { sub pandora_get_initial_copyright_notice { # PandoraFMS product name my $name = $ENV{'PANDORA_RB_COPYRIGHT_NOTICE'}; - return 'Artica ST' unless (defined ($name) && $name ne ''); + return 'Pandora FMS' unless (defined ($name) && $name ne ''); return $name; } diff --git a/pandora_server/lib/PandoraFMS/DB.pm b/pandora_server/lib/PandoraFMS/DB.pm index 7ed8d9e2f8..a5a6d98b80 100644 --- a/pandora_server/lib/PandoraFMS/DB.pm +++ b/pandora_server/lib/PandoraFMS/DB.pm @@ -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. ########################################################################## diff --git a/pandora_server/lib/PandoraFMS/DataServer.pm b/pandora_server/lib/PandoraFMS/DataServer.pm index e003653b02..896bbf935f 100644 --- a/pandora_server/lib/PandoraFMS/DataServer.pm +++ b/pandora_server/lib/PandoraFMS/DataServer.pm @@ -313,8 +313,6 @@ sub data_consumer ($$) { enterprise_hook('process_xml_connections', [$self->getConfig (), $file_name, $xml_data, $self->getDBH ()]); } elsif (defined($xml_data->{'ipam_source'})) { enterprise_hook('process_xml_ipam', [$self->getConfig (), $file_name, $xml_data, $self->getDBH ()]); - } elsif (defined($xml_data->{'network_matrix'})){ - process_xml_matrix_network( $self->getConfig(), $xml_data, $self->getDBH()); } else { process_xml_data ($self->getConfig (), $file_name, $xml_data, $self->getServerID (), $self->getDBH ()); } @@ -1130,45 +1128,6 @@ sub process_events_dataserver { return; } - -########################################################################## -# Process events in the XML. -########################################################################## -sub process_xml_matrix_network { - my ($pa_config, $data, $dbh) = @_; - - my $utimestamp = $data->{'network_matrix'}->[0]->{'utimestamp'}; - my $content = $data->{'network_matrix'}->[0]->{'content'}; - return unless defined($utimestamp) && defined($content); - - # Try to decode the base64 inside - my $matrix_info; - eval { - $matrix_info = decode_json(decode_base64($content)); - }; - - if ($@) { - logger($pa_config, "Error processing base64 matrix data '$content'.", 5); - return; - } - foreach my $source (keys %$matrix_info) { - foreach my $destination (keys %{$matrix_info->{$source}}) { - my $matrix_single_data = $matrix_info->{$source}->{$destination}; - $matrix_single_data->{'source'} = $source; - $matrix_single_data->{'destination'} = $destination; - $matrix_single_data->{'utimestamp'} = $utimestamp; - eval { - db_process_insert($dbh, 'id', 'tnetwork_matrix', $matrix_single_data); - }; - if ($@) { - logger($pa_config, "Error inserted matrix data. Source: $source, destination: $destination, utimestamp: $utimestamp.", 5); - } - } - } - - return; -} - ########################################################################## # Get a lock on the given agent. Return 1 on success, 0 otherwise. ########################################################################## diff --git a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm index bce36263d3..d331c7986d 100644 --- a/pandora_server/lib/PandoraFMS/DiscoveryServer.pm +++ b/pandora_server/lib/PandoraFMS/DiscoveryServer.pm @@ -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: /discovery//