interactive = $interactive; if ($source === false) { $this->enabled = false; $this->sourceId = null; $this->targetGroups = null; $this->targetUsers = null; } else { $this->enabled = (bool) $source['enabled']; $this->sourceId = $source['id']; } return $this; } /** * Warn a message. * * @param string $msg Message. * * @return void */ public function warn(string $msg) { if ($this->verbose === true) { echo date('M j G:i:s').' ConsoleSupervisor: '.$msg."\n"; } } /** * Manage scheduled tasks (basic). * * @return void */ public function runBasic() { // Ensure functions are installed and up to date. enterprise_hook('cron_extension_install_functions'); /* * PHP configuration warnings: * NOTIF.PHP.SAFE_MODE * NOTIF.PHP.INPUT_TIME * NOTIF.PHP.EXECUTION_TIME * NOTIF.PHP.UPLOAD_MAX_FILESIZE * NOTIF.PHP.MEMORY_LIMIT * NOTIF.PHP.DISABLE_FUNCTIONS * NOTIF.PHP.CHROMIUM * NOTIF.PHP.VERSION * NOTIF.PHP.VERSION.SUPPORT */ $this->checkPHPSettings(); /* * Check license. * NOTIF.LICENSE.EXPIRATION */ $this->checkLicense(); /* * Check component statuses (servers down - frozen). * NOTIF.SERVER.STATUS.ID_SERVER */ $this->checkPandoraServers(); /* * Check at least 1 server running in master mode. * NOTIF.SERVER.MASTER */ $this->checkPandoraServerMasterAvailable(); /* * Check if CRON is running. * NOTIF.CRON.CONFIGURED */ if (enterprise_installed()) { $this->checkCronRunning(); } /* * Check if instance is registered. * NOTIF.UPDATEMANAGER.REGISTRATION */ $this->checkUpdateManagerRegistration(); /* * Check if has API access. * NOTIF.API.ACCESS */ $this->checkApiAccess(); /* * Check if there're new messages in UM. * NOTIF.UPDATEMANAGER.MESSAGES */ $this->getUMMessages(); /* * Check if the Server and Console has * the same versions. * NOTIF.SERVER.MISALIGNED */ $this->checkConsoleServerVersions(); /* * Check if AllowOverride is None or All. * NOTIF.ALLOWOVERIDE.MESSAGE */ $this->checkAllowOverrideEnabled(); /* * Check if the Pandora Console log * file remains in old location. * NOTIF.PANDORACONSOLE.LOG.OLD */ $this->checkPandoraConsoleLogOldLocation(); /* * Check if the audit log file * remains in old location. * NOTIF.AUDIT.LOG.OLD */ $this->checkAuditLogOldLocation(); /* * Check if performance variables are corrects */ $this->checkPerformanceVariables(); /* * Checks if sync queue is longer than limits. * NOTIF.SYNCQUEUE.LENGTH */ if (is_metaconsole() === true) { $this->checkSyncQueueLength(); $this->checkSyncQueueStatus(); } /* * Check number of agents is equals and more than 200. * NOTIF.ACCESSSTASTICS.PERFORMANCE */ $this->checkAccessStatisticsPerformance(); /* * Checkc agent missing libraries. * NOTIF.AGENT.LIBRARY */ if ((bool) enterprise_installed() === true) { $this->checkLibaryError(); } /* * Check MYSQL Support Version */ $this->checkMYSQLSettings(); } /** * Manage scheduled tasks. * * @return void */ public function run() { global $config; $this->maintenanceOperations(); if ($this->enabled === false) { // Notifications not enabled. return; } if ($this->sourceId === null) { // Source not detected. return; } if ($this->verbose === true) { if (enterprise_hook('cron_supervisor_lock') === false) { // Cannot continue. Locked. exit; } } // Enterprise support. if (file_exists($config['homedir'].'/'.ENTERPRISE_DIR.'/load_enterprise.php')) { include_once $config['homedir'].'/'.ENTERPRISE_DIR.'/load_enterprise.php'; } // Automatic checks launched by supervisor. $this->warn('running.'); /* * Check license. * NOTIF.LICENSE.EXPIRATION * NOTIF.LICENSE.LIMITED */ $this->checkLicense(); /* * Check number of files in attachment: * NOTIF.FILES.ATTACHMENT */ $this->checkAttachment(); /* * Files in data_in: * NOTIF.FILES.DATAIN (>1000) * NOTIF.FILES.DATAIN.BADXML (>150) */ $this->checkDataIn(); /* * Check module queues not growing: * NOTIF.SERVER.QUEUE.ID_SERVER */ $this->checkServers(); /* * Check component statuses (servers down - frozen). * NOTIF.SERVER.STATUS.ID_SERVER */ $this->checkPandoraServers(); /* * Check at least 1 server running in master mode. * NOTIF.SERVER.MASTER */ $this->checkPandoraServerMasterAvailable(); /* * PHP configuration warnings: * NOTIF.PHP.SAFE_MODE * NOTIF.PHP.INPUT_TIME * NOTIF.PHP.EXECUTION_TIME * NOTIF.PHP.UPLOAD_MAX_FILESIZE * NOTIF.PHP.MEMORY_LIMIT * NOTIF.PHP.DISABLE_FUNCTIONS * NOTIF.PHP.CHROMIUM * NOTIF.PHP.VERSION * NOTIF.PHP.VERSION.SUPPORT */ $this->checkPHPSettings(); /* * Check connection with historical DB (if enabled). * NOTIF.HISTORYDB */ $this->checkPandoraHistoryDB(); /* * Check pandoradb running in main DB. * Check pandoradb running in historical DB. * NOTIF.PANDORADB * NOTIF.PANDORADB.HISTORICAL */ $this->checkPandoraDBMaintenance(); /* * Check historical DB MR version. * NOTIF.HISTORYDB.MR */ $this->checkPandoraHistoryDBMR(); /* * Check external components. * NOTIF.EXT.ELASTICSEARCH * NOTIF.EXT.LOGSTASH * */ $this->checkExternalComponents(); /* * Check Metaconsole synchronization issues. * NOTIF.METACONSOLE.DB_CONNECTION */ $this->checkMetaconsole(); /* * Check incoming scheduled downtimes (< 15d). * NOTIF.DOWNTIME */ $this->checkDowntimes(); /* * Check if instance is registered. * NOTIF.UPDATEMANAGER.REGISTRATION */ $this->checkUpdateManagerRegistration(); /* * Check if has API access. * NOTIF.API.ACCESS */ $this->checkApiAccess(); /* * Check if event storm protection is activated. * NOTIF.MISC.EVENTSTORMPROTECTION */ $this->checkEventStormProtection(); /* * Check if develop_bypass is enabled. * NOTIF.MISC.DEVELOPBYPASS */ $this->checkDevelopBypass(); /* * Check if fontpath exists. * NOTIF.MISC.FONTPATH */ $this->checkFont(); /* * Check if default user and password exists. * NOTIF.SECURITY.DEFAULT_PASSWORD */ $this->checkDefaultPassword(); /* * Check if there're new updates. * NOTIF.UPDATEMANAGER.OPENSETUP * NOTIF.UPDATEMANAGER.UPDATE */ $this->checkUpdates(); /* * Check if there're new minor updates available. * NOTIF.UPDATEMANAGER.MINOR */ $this->checkMinorRelease(); if ((bool) enterprise_installed() === true) { // Release the lock. enterprise_hook('cron_supervisor_release_lock'); } /* * Check if CRON is running. * NOTIF.CRON.CONFIGURED */ if (enterprise_installed()) { $this->checkCronRunning(); } /* * Check if instance is registered. * NOTIF.UPDATEMANAGER.REGISTRATION */ $this->checkUpdateManagerRegistration(); /* * Check if has API access. * NOTIF.API.ACCESS */ $this->checkApiAccess(); /* * Check if there're new messages in UM. * NOTIF.UPDATEMANAGER.MESSAGES */ $this->getUMMessages(); /* * Check if the Server and Console has * the same versions. * NOTIF.SERVER.MISALIGNED */ $this->checkConsoleServerVersions(); /* * Check if AllowOverride is None or All. * NOTIF.ALLOWOVERRIDE.MESSAGE */ $this->checkAllowOverrideEnabled(); /* * Check if HA status. */ if ((bool) enterprise_installed() === true) { $this->checkHaStatus(); } /* * Check if the audit log file * remains in old location. */ $this->checkAuditLogOldLocation(); /* * Check if performance variables are corrects */ $this->checkPerformanceVariables(); /* * Checks if sync queue is longer than limits. * NOTIF.SYNCQUEUE.LENGTH */ if (is_metaconsole() === true) { $this->checkSyncQueueLength(); $this->checkSyncQueueStatus(); } /* * Check number of agents is equals and more than 200. * NOTIF.ACCESSSTASTICS.PERFORMANCE */ $this->checkAccessStatisticsPerformance(); /* * Checkc agent missing libraries. * NOTIF.AGENT.LIBRARY */ if ((bool) enterprise_installed() === true) { $this->checkLibaryError(); } /* * Check MYSQL Support Version * */ $this->checkMYSQLSettings(); } /** * Check if performance variables are corrects * * @return void */ public function checkPerformanceVariables() { global $config; $names = [ 'event_purge' => 'Max. days before events are deleted', 'trap_purge' => 'Max. days before traps are deleted', 'audit_purge' => 'Max. days before audited events are deleted', 'string_purge' => 'Max. days before string data is deleted', 'gis_purge' => 'Max. days before GIS data is deleted', 'days_purge' => 'Max. days before purge', 'days_compact' => 'Max. days before data is compacted', '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', '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', 'small_operation_step_datos_purge' => 'Small Operation Step to purge old data', 'row_limit_csv' => 'Row limit in csv log', 'limit_parameters_massive' => 'Limit for bulk operations', 'block_size' => 'User block size for pagination', 'global_block_size' => 'Global block size for pagination', 'short_module_graph_data' => 'Data precision', 'graph_precision' => 'Data precision in graphs', ]; $variables = (array) json_decode(io_safe_output($config['performance_variables_control'])); foreach ($variables as $variable => $values) { if (empty($config[$variable]) === true || $config[$variable] === '') { continue; } $message = ''; $limit_value = ''; $url = ''; if ($config[$variable] > $values->max) { $message = 'Check the setting of %s, a value greater than %s is not recommended'; if ($variable === 'block_size') { $message .= '. (User: '.$config['id_user'].')'; } $limit_value = $values->max; } if ($config[$variable] < $values->min) { $message = 'Check the setting of %s, a value less than %s is not recommended'; $limit_value = $values->min; } if ($limit_value !== '' && $message !== '') { if (is_metaconsole() === true) { $url = '__url__index.php?sec=advanced&sec2=advanced/metasetup'; } else { $url = '__url__/index.php?sec=general&sec2=godmode/setup/setup'; } if ($variable === 'block_size') { if (is_metaconsole() === true) { $url = '__url__index.php?sec=gusuarios&sec2=godmode/users/configure_user&edit_user=1&pure=0&id_user='.$config['id_user']; } else { $url = '__url__/index.php?sec=gusuarios&sec2=godmode/users/configure_user&edit_user=1&pure=0&id_user='.$config['id_user']; } } if ($variable === 'global_block_size') { if (is_metaconsole() === true) { $url = '__url__index.php?sec=advanced&sec2=advanced/metasetup&pure=0&tab=visual'; } else { $url = '__url__/index.php?sec=gsetup&sec2=godmode/setup/setup§ion=vis'; } } $this->notify( [ 'type' => 'NOTIF.VARIABLES.PERFORMANCE.'.$variable, 'title' => __('Incorrect config value'), 'message' => __( $message, $names[$variable], $limit_value ), 'url' => $url, ] ); } } } /** * Executes console maintenance operations. Executed ALWAYS through CRON. * * @return void */ public function maintenanceOperations() { } /** * Check number of agents and disable agentaccess token if number * is equals and more than 200. * * @return void */ public function checkAccessStatisticsPerformance() { global $config; $total_agents = db_get_value('count(*)', 'tagente'); if ($total_agents >= 200) { if ((int) $config['agentaccess'] !== 0) { db_process_sql_update('tconfig', ['value' => 0], ['token' => 'agentaccess']); $this->notify( [ 'type' => 'NOTIF.ACCESSSTASTICS.PERFORMANCE', 'title' => __('Access statistics performance'), 'message' => __( 'Usage of agent access statistics IS NOT RECOMMENDED on systems with more than 200 agents due performance penalty' ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } } else { $this->cleanNotifications('NOTIF.ACCESSSTASTICS.PERFORMANCE'); } } /** * Update targets for given notification using object targets. * * @param array $notification Current notification. * @param boolean $send_mails Only update db targets, no email. * * @return void */ public function updateTargets( array $notification, bool $send_mails=true ) { $notification_id = $notification['id_mensaje']; $blacklist = []; if (is_array($this->targetUsers) === true && count($this->targetUsers) > 0 ) { // Process user targets. $insertion_string = ''; $users_sql = 'INSERT IGNORE INTO tnotification_user(id_mensaje,id_user)'; foreach ($this->targetUsers as $user) { $insertion_string .= sprintf( '(%d,"%s")', $notification_id, $user['id_user'] ); $insertion_string .= ','; if ($send_mails === true) { // Send mail. if (isset($user['also_mail']) && $user['also_mail'] == 1) { enterprise_hook( 'send_email_user', [ $user['id_user'], io_safe_output($notification['mensaje']).'

'.$notification['url'], io_safe_output($notification['subject']), ] ); array_push($blacklist, $user['id_user']); } } } $insertion_string = substr($insertion_string, 0, -1); db_process_sql($users_sql.' VALUES '.$insertion_string); } if (is_array($this->targetGroups) === true && count($this->targetGroups) > 0 ) { // Process group targets. $insertion_string = ''; $groups_sql = 'INSERT IGNORE INTO tnotification_group(id_mensaje,id_group)'; foreach ($this->targetGroups as $group) { $insertion_string .= sprintf( '(%d,"%s")', $notification_id, $group['id_group'] ); $insertion_string .= ','; if ($send_mails === true) { // Send mail. if (isset($group['also_mail']) && $group['also_mail'] == 1) { enterprise_hook( 'send_email_group', [ $group['id_group'], io_safe_output($notification['mensaje']).'

'.$notification['url'], io_safe_output($notification['subject']), null, $blacklist, ] ); } } } $insertion_string = substr($insertion_string, 0, -1); db_process_sql($groups_sql.' VALUES '.$insertion_string); } } /** * Generates notifications for target users and groups. * * @param array $data Message to be delivered: * - boolean status (false: notify, true: do not notify) * - string title * - string message * - string url. * @param integer $source_id Target source_id, by default $this->sourceId. * @param integer $max_age Maximum age for generated notification. * * @return void */ public function notify( array $data, int $source_id=0, int $max_age=SECONDS_1DAY ) { // Uses 'check failed' logic. if (is_array($data) === false) { // Skip. return; } if ($source_id === 0) { $source_id = $this->sourceId; } static $_cache_targets; $key = $source_id.'|'.$data['type']; if ($_cache_targets === null) { $_cache_targets = []; } if (isset($_cache_targets[$key]) === true && $_cache_targets[$key] !== null ) { $targets = $_cache_targets[$key]; } else { $targets = get_notification_source_targets( $source_id, $data['type'] ); $this->targetGroups = ($targets['groups'] ?? null); $this->targetUsers = ($targets['users'] ?? null); $_cache_targets[$key] = $targets; } switch ($data['type']) { case 'NOTIF.LICENSE.LIMITED': $max_age = 0; break; case 'NOTIF.FILES.ATTACHMENT': case 'NOTIF.FILES.DATAIN': case 'NOTIF.FILES.DATAIN.BADXML': case 'NOTIF.PHP.SAFE_MODE': case 'NOTIF.PHP.INPUT_TIME': case 'NOTIF.PHP.EXECUTION_TIME': case 'NOTIF.PHP.UPLOAD_MAX_FILESIZE': case 'NOTIF.PHP.MEMORY_LIMIT': case 'NOTIF.PHP.DISABLE_FUNCTIONS': case 'NOTIF.PHP.CHROMIUM': case 'NOTIF.PHP.VERSION': case 'NOTIF.PHP.VERSION.SUPPORT': case 'NOTIF.HISTORYDB': case 'NOTIF.PANDORADB': case 'NOTIF.PANDORADB.HISTORICAL': case 'NOTIF.HISTORYDB.MR': case 'NOTIF.EXT.ELASTICSEARCH': case 'NOTIF.METACONSOLE.DB_CONNECTION': case 'NOTIF.DOWNTIME': case 'NOTIF.UPDATEMANAGER.REGISTRATION': case 'NOTIF.API.ACCESS': case 'NOTIF.MISC.EVENTSTORMPROTECTION': case 'NOTIF.MISC.DEVELOPBYPASS': case 'NOTIF.MISC.FONTPATH': case 'NOTIF.SECURITY.DEFAULT_PASSWORD': case 'NOTIF.UPDATEMANAGER.OPENSETUP': case 'NOTIF.UPDATEMANAGER.UPDATE': case 'NOTIF.UPDATEMANAGER.MINOR': case 'NOTIF.UPDATEMANAGER.MESSAGES': case 'NOTIF.CRON.CONFIGURED': case 'NOTIF.ALLOWOVERRIDE.MESSAGE': case 'NOTIF.HAMASTER.MESSAGE': case 'NOTIF.MYSQL.VERSION': default: // NOTIF.SERVER.STATUS. // NOTIF.SERVER.STATUS.ID_SERVER. // NOTIF.SERVER.QUEUE.ID_SERVER. // NOTIF.SERVER.MASTER. // NOTIF.SERVER.STATUS.ID_SERVER. if (preg_match('/^NOTIF.SERVER/', $data['type']) === true) { // Send notification once a day. $max_age = SECONDS_1DAY; } // Else ignored. break; } // Get previous notification. $prev = db_get_row( 'tmensajes', 'subtype', $data['type'], false, false ); if ($prev !== false && (time() - $prev['timestamp']) > $max_age ) { // Clean previous notification. $this->cleanNotifications($data['type']); } else if ($prev !== false) { // Avoid creation. Previous notification is still valid. // Update message with latest information. $r = db_process_sql_update( 'tmensajes', [ 'mensaje' => io_safe_input($data['message']), 'subject' => io_safe_input($data['title']), ], ['id_mensaje' => $prev['id_mensaje']] ); $this->updateTargets($prev, false); return; } if (isset($data['type']) === false) { $data['type'] = ''; } // Create notification. $notification = []; $notification['timestamp'] = time(); $notification['id_source'] = $source_id; $notification['mensaje'] = io_safe_input($data['message']); $notification['subject'] = io_safe_input($data['title']); $notification['subtype'] = $data['type']; $notification['url'] = io_safe_input($data['url']); $id = db_process_sql_insert('tmensajes', $notification); if ($id === false) { // Failed to generate notification. $this->warn('Failed to generate notification'); return; } // Update reference to update targets. $notification['id_mensaje'] = $id; $this->updateTargets($notification); } /** * Deletes useless notifications. * * @param string $subtype Subtype to be deleted. * * @return mixed False in case of error or invalid values passed. * Affected rows otherwise */ public function cleanNotifications(string $subtype) { $not_count = db_get_value_sql( sprintf( 'SELECT count(*) as n FROM tmensajes WHERE subtype like "%s"', $subtype ) ); if ($not_count > 0) { return db_process_sql_delete( 'tmensajes', sprintf('subtype like "%s"', $subtype) ); } return true; } /** * Check license status and validity. * * @return boolean Return true if license is valid, false if not. */ public function checkLicense() { global $config; $license = enterprise_hook('license_get_info'); if ($license === ENTERPRISE_NOT_HOOK) { return false; } $days_to_expiry = ((strtotime($license['expiry_date']) - time()) / (60 * 60 * 24)); // Limited mode. if (isset($config['limited_mode'])) { // Warn user if license is going to expire in 15 days or less. $this->notify( [ 'type' => 'NOTIF.LICENSE.LIMITED', 'title' => __('Limited mode.'), 'message' => io_safe_output($config['limited_mode']), 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/setup/license', ] ); } else { $this->cleanNotifications('NOTIF.LICENSE.LIMITED'); } // Expiry. if (($days_to_expiry <= 15) && ($days_to_expiry > 0) && ((is_user_admin($config['id_user'])) || (check_acl($config['id_user'], 0, 'PM'))) ) { if ($config['license_mode'] == 1) { $title = __('License is about to expire'); $msg = 'Your license will expire in %d days. Please, contact our sales department.'; } else { $title = __('Support is about to expire'); $msg = 'Your support license will expire in %d days. Please, contact our sales department.'; } // Warn user if license is going to expire in 15 days or less. $this->notify( [ 'type' => 'NOTIF.LICENSE.EXPIRATION', 'title' => $title, 'message' => __( $msg, $days_to_expiry ), 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/setup/license', ] ); } else if (($days_to_expiry <= 0) && ((is_user_admin($config['id_user'])) || (check_acl($config['id_user'], 0, 'PM')))) { if ($config['license_mode'] == 1) { $title = __('Expired license'); $msg = __('Your license has expired. Please, contact our sales department.'); } else { $title = __('Support expired'); $msg = __('This license is outside of support. Please, contact our sales department.'); } // Warn user, license has expired. $this->notify( [ 'type' => 'NOTIF.LICENSE.EXPIRATION', 'title' => $title, 'message' => $msg, 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/setup/license', ] ); return false; } else { $this->cleanNotifications('NOTIF.LICENSE.EXPIRATION'); } return true; } /** * Count files in target path. * * @param string $path Path to be checked. * @param string $regex Regular expression to find files. * @param integer $max_files Maximum number of files to find. * * @return integer Number of files in target path. */ public function countFiles( string $path='', string $regex='', int $max_files=500 ) { if (empty($path) === true) { return -1; } $nitems = 0; // Count files up to max_files. $dir = opendir($path); if ($dir !== false) { // Used instead of glob to avoid check directories with // more than 1M files. while (false !== ($file = readdir($dir)) && $nitems <= $max_files) { if ($file != '.' && $file != '..') { if (empty($regex) === false) { if (preg_match($regex, $file) === 1) { $nitems++; continue; } } else { $nitems++; } } } closedir($dir); } return $nitems; } /** * Check excesive files in attachment directory. * * @return void */ public function checkAttachment() { global $config; if (is_writable($config['attachment_store']) !== true) { $this->notify( [ 'type' => 'NOTIF.WRITABLE.ATTACHMENT', 'title' => __('Attachment directory is not writable'), 'message' => __( 'Directory %s is not writable. Please, configure corresponding permissions.', $config['attachment_store'] ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=general', ] ); return; } else { $this->cleanNotifications('NOTIF.WRITABLE.ATTACHMENT'); } $filecount = $this->countFiles( $config['attachment_store'], '', $config['num_files_attachment'] ); if ($filecount > $config['num_files_attachment']) { $this->notify( [ 'type' => 'NOTIF.FILES.ATTACHMENT', 'title' => __('There are too many files in attachment directory'), 'message' => __( 'There are more than %d files in attachment, consider cleaning up attachment directory manually.', $config['num_files_attachment'] ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } else { $this->cleanNotifications('NOTIF.FILES.ATTACHMENT'); } } /** * Check excesive files in data_in directory. * * @return void */ public function checkDataIn() { global $config; $remote_config_dir = (string) io_safe_output($config['remote_config']); if (enterprise_installed() && isset($config['license_nms']) && $config['license_nms'] != 1 ) { if (is_readable($remote_config_dir) !== true) { $this->notify( [ 'type' => 'NOTIF.PERMISSIONS.REMOTE_CONFIG', 'title' => __('Remote configuration directory is not readable'), 'message' => __( 'Remote configuration directory %s is not readable. Please, adjust configuration.', $remote_config_dir ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=general', ] ); return; } else { $this->cleanNotifications( 'NOTIF.PERMISSIONS.REMOTE_CONFIG' ); } if (is_writable($remote_config_dir.'/conf') !== true) { $this->notify( [ 'type' => 'NOTIF.PERMISSIONS.REMOTE_CONFIG.CONF', 'title' => __('Remote configuration directory is not writable'), 'message' => __( 'Remote configuration directory %s is not writable. Please, adjust configuration.', $remote_config_dir.'/conf' ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=general', ] ); } else { $this->cleanNotifications( 'NOTIF.PERMISSIONS.REMOTE_CONFIG.CONF' ); } if (is_writable($remote_config_dir.'/collections') !== true) { $this->notify( [ 'type' => 'NOTIF.PERMISSIONS.REMOTE_CONFIG.COLLECTIONS', 'title' => __('Remote collections directory is not writable'), 'message' => __( 'Collections directory %s is not writable. Please, adjust configuration.', $remote_config_dir.'/collections' ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=general', ] ); } else { $this->cleanNotifications( 'NOTIF.PERMISSIONS.REMOTE_CONFIG.COLLECTIONS' ); } if (is_writable($remote_config_dir.'/md5') !== true) { $this->notify( [ 'type' => 'NOTIF.PERMISSIONS.REMOTE_CONFIG.MD5', 'title' => __('Remote md5 directory is not writable'), 'message' => __( 'MD5 directory %s is not writable. Please, adjust configuration.', $remote_config_dir.'/md5' ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=general', ] ); } else { $this->cleanNotifications( 'NOTIF.PERMISSIONS.REMOTE_CONFIG.MD5' ); } } else { $this->cleanNotifications('NOTIF.PERMISSIONS.REMOTE_CONF%'); } $MAX_FILES_DATA_IN = 1000; $MAX_BADXML_FILES_DATA_IN = 150; $filecount = $this->countFiles( $remote_config_dir, '', $MAX_FILES_DATA_IN ); // If cannot open directory, count is '-1', skip. if ($filecount > $MAX_FILES_DATA_IN) { $this->notify( [ 'type' => 'NOTIF.FILES.DATAIN', 'title' => __('There are too much files in spool').'.', 'message' => __( 'There are more than %d files in %s. Consider checking DataServer performance', $MAX_FILES_DATA_IN, $remote_config_dir ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } else { $this->cleanNotifications('NOTIF.FILES.DATAIN'); } $filecount = $this->countFiles( $remote_config_dir, '/^.*BADXML$/', $MAX_BADXML_FILES_DATA_IN ); // If cannot open directory, count is '-1', skip. if ($filecount > $MAX_BADXML_FILES_DATA_IN) { $this->notify( [ 'type' => 'NOTIF.FILES.DATAIN.BADXML', 'title' => __('There are too many BADXML files in spool'), 'message' => __( 'There are more than %d files in %s. Consider checking software agents.', $MAX_BADXML_FILES_DATA_IN, $remote_config_dir ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } else { $this->cleanNotifications('NOTIF.FILES.DATAIN.BADXML'); } } /** * Check growing queues in servers. * * @return void */ public function checkServers() { global $config; include_once $config['homedir'].'/include/functions_servers.php'; $idx_file = $config['attachment_store'].'/.cron.supervisor.servers.idx'; $MAX_QUEUE = 1500; $total_modules = servers_get_total_modules(); $queue_state = []; $previous = []; $new = []; if (file_exists($idx_file) === true) { // Read previous values from file. $previous = json_decode(file_get_contents($idx_file), true); } // DataServer queue status. $queue_state = db_get_all_rows_sql( 'SELECT id_server,name,server_type,queued_modules,status FROM tserver ORDER BY 1' ); $time = time(); if (is_array($queue_state) === true) { foreach ($queue_state as $queue) { $key = $queue['id_server']; $type = $queue['server_type']; $new_data[$key] = $queue['queued_modules']; $max_grown = 0; if (is_array($total_modules) && isset($total_modules[$queue['server_type']]) ) { $max_grown = ($total_modules[$queue['server_type']] * 0.40); } if ($total_modules[$queue['server_type']] < self::MIN_PERFORMANCE_MODULES) { $this->cleanNotifications('NOTIF.SERVER.QUEUE.'.$key); // Skip. continue; } // Compare queue increments in a not over 900 seconds. if (empty($previous[$key]['modules']) || ($time - $previous[$key]['utime']) > 900 ) { $previous[$key]['modules'] = 0; } $modules_queued = ($queue['queued_modules'] - $previous[$key]['modules']); // 40% Modules queued since last check. If any. if ($max_grown > 0 && $modules_queued > $max_grown ) { $msg = 'Queue has grown %d modules. Total %d'; if ($modules_queued <= 0) { $msg = 'Queue is decreasing in %d modules. But there are %d queued.'; $modules_queued *= -1; } $this->notify( [ 'type' => 'NOTIF.SERVER.QUEUE.'.$key, 'title' => __( '%s (%s) is lacking performance.', servers_get_server_string_name($type), $queue['name'] ), 'message' => __( $msg, $modules_queued, $queue['queued_modules'] ), 'url' => '__url__/index.php?sec=gservers&sec2=godmode/servers/modificar_server&refr=60', ] ); } else { $this->cleanNotifications('NOTIF.SERVER.QUEUE.'.$key); } $new[$key]['modules'] = $queue['queued_modules']; $new[$key]['utime'] = $time; } // Update file content. file_put_contents($idx_file, json_encode($new)); } else { // No queue data, ignore. unlink($idx_file); // Clean notifications. $this->cleanNotifications('NOTIF.SERVER.QUEUE.%'); } } /** * Check Pandora component statuses. * * @return void */ public function checkPandoraServers() { global $config; $servers = db_get_all_rows_sql( 'SELECT id_server, name, server_type, server_keepalive, status, unix_timestamp() - unix_timestamp(keepalive) as downtime FROM tserver WHERE unix_timestamp() - unix_timestamp(keepalive) > server_keepalive' ); if ($servers === false) { $nservers = db_get_value_sql( 'SELECT count(*) as nservers FROM tserver' ); if ($nservers == 0) { $url = 'https://pandorafms.com/manual/en/documentation/02_installation/04_configuration'; if ($config['language'] == 'es') { $url = 'https://pandorafms.com/manual/es/documentation/02_installation/04_configuration'; } $this->notify( [ 'type' => 'NOTIF.SERVER.STATUS', 'title' => __('No servers available.'), 'message' => __('There are no servers registered in this console. Please, check installation guide.'), 'url' => $url, ] ); } // At this point there's no servers with issues. $this->cleanNotifications('NOTIF.SERVER.STATUS%'); return; } else { // Clean notifications. Only show notif for down servers // ONLY FOR RECOVERED ONES. $servers_working = db_get_all_rows_sql( 'SELECT id_server, name, server_type, server_keepalive, status, unix_timestamp() - unix_timestamp(keepalive) as downtime FROM tserver WHERE unix_timestamp() - unix_timestamp(keepalive) <= server_keepalive AND status = 1' ); if (is_array($servers_working) === true) { foreach ($servers_working as $server) { $this->cleanNotifications( 'NOTIF.SERVER.STATUS.'.$server['id_server'] ); } } } foreach ($servers as $server) { if ($server['server_type'] == SERVER_TYPE_ENTERPRISE_SATELLITE) { if ($server['downtime'] < ($server['server_keepalive'] * 2)) { // Satellite uses different keepalive mode. continue; } } if ($server['status'] == 1) { // Fatal error. Component has die. $msg = __( '%s (%s) has crashed.', servers_get_server_string_name($server['server_type']), $server['name'] ); $description = __( '%s (%s) has crashed, please check log files.', servers_get_server_string_name($server['server_type']), $server['name'] ); } else { // Non-fatal error. Controlated exit. Component is not running. $msg = __( '%s (%s) is not running.', servers_get_server_string_name($server['server_type']), $server['name'] ); $description = __( '%s (%s) is not running. Please, check configuration file or remove this server from server list.', servers_get_server_string_name($server['server_type']), $server['name'] ); } $this->notify( [ 'type' => 'NOTIF.SERVER.STATUS.'.$server['id_server'], 'title' => $msg, 'message' => $description, 'url' => '__url__/index.php?sec=gservers&sec2=godmode/servers/modificar_server&refr=60', ] ); } } /** * Checks if there's at last one server running in master mode. * * @return void */ public function checkPandoraServerMasterAvailable() { global $config; $n_masters = db_get_value_sql( 'SELECT count(*) as n FROM tserver WHERE unix_timestamp() - unix_timestamp(keepalive) <= server_keepalive AND master > 0 AND status = 1' ); if ($n_masters === false) { // Failed to retrieve server list. return; } if ($n_masters <= 0) { // No server running in master. $url = 'https://pandorafms.com/manual/en/documentation/02_installation/04_configuration#master'; if ($config['language'] == 'es') { $url = 'https://pandorafms.com/manual/es/documentation/02_installation/04_configuration#master'; } $this->notify( [ 'type' => 'NOTIF.SERVER.MASTER', 'title' => __('No master servers found.'), 'message' => __('At least one server must be defined to run as master. Please, check documentation.'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.SERVER.MASTER%'); } } /** * Checks PHP settings to be correct. Generates system notifications if not. * * @return void */ public function checkPHPSettings() { global $config; $PHPupload_max_filesize = config_return_in_bytes( ini_get('upload_max_filesize') ); // PHP configuration. $PHPmax_input_time = ini_get('max_input_time'); $PHPmemory_limit = config_return_in_bytes(ini_get('memory_limit')); $PHPmax_execution_time = ini_get('max_execution_time'); $PHPsafe_mode = ini_get('safe_mode'); $PHPdisable_functions = ini_get('disable_functions'); $PHPupload_max_filesize_min = config_return_in_bytes('800M'); $PHPmemory_limit_min = config_return_in_bytes('800M'); $PHPSerialize_precision = ini_get('serialize_precision'); if (is_metaconsole() === true) { $PHPmemory_limit_min = config_return_in_bytes('-1'); } // Chromium status. $chromium_dir = io_safe_output($config['chromium_path']); $result_ejecution = exec($chromium_dir.' --version'); // PHP version checks. $php_version = phpversion(); $php_version_array = explode('.', $php_version); if ($PHPsafe_mode === '1') { $url = 'http://php.net/manual/en/features.safe-mode.php'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/features.safe-mode.php'; } $this->notify( [ 'type' => 'NOTIF.PHP.SAFE_MODE', 'title' => __('PHP safe mode is enabled. Some features may not work properly'), 'message' => __('To disable it, go to your PHP configuration file (php.ini) and put safe_mode = Off (Do not forget to restart apache process after changes)'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.SAFE_MODE'); } if ($PHPmax_input_time !== '-1') { $url = 'http://php.net/manual/en/info.configuration.php#ini.max-input-time'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/info.configuration.php#ini.max-input-time'; } $this->notify( [ 'type' => 'NOTIF.PHP.INPUT_TIME', 'title' => sprintf( __('%s value in PHP configuration is not recommended'), 'max_input_time' ), 'message' => sprintf( __('Recommended value is %s'), '-1 ('.__('Unlimited').')' ).'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator (Do not forget to restart Apache process after)'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.INPUT_TIME'); } if ((int) $PHPmax_execution_time !== 0) { $url = 'http://php.net/manual/en/info.configuration.php#ini.max-execution-time'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/info.configuration.php#ini.max-execution-time'; } $this->notify( [ 'type' => 'NOTIF.PHP.EXECUTION_TIME', 'title' => sprintf( __("Not recommended '%s' value in PHP configuration"), 'max_execution_time' ), 'message' => sprintf( __('Recommended value is: %s'), '0 ('.__('Unlimited').')' ).'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator (Dont forget restart apache process after changes)'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.EXECUTION_TIME'); } if ($PHPupload_max_filesize < $PHPupload_max_filesize_min) { $url = 'http://php.net/manual/en/ini.core.php#ini.upload-max-filesize'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/ini.core.php#ini.upload-max-filesize'; } $this->notify( [ 'type' => 'NOTIF.PHP.UPLOAD_MAX_FILESIZE', 'title' => sprintf( __("Not recommended '%s' value in PHP configuration"), 'upload_max_filesize' ), 'message' => sprintf( __('Recommended value is: %s'), sprintf(__('%s or greater'), '800M') ).'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator (Dont forget restart apache process after changes)'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.UPLOAD_MAX_FILESIZE'); } if ($PHPmemory_limit < $PHPmemory_limit_min && (int) $PHPmemory_limit !== -1) { $url = 'http://php.net/manual/en/ini.core.php#ini.memory-limit'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/ini.core.php#ini.memory-limit'; } $recommended_memory = '800M'; if (is_metaconsole() === true) { $recommended_memory = '-1'; } $this->notify( [ 'type' => 'NOTIF.PHP.MEMORY_LIMIT', 'title' => sprintf( __("Not recommended '%s' value in PHP configuration"), 'memory_limit' ), 'message' => sprintf( __('Recommended value is: %s'), sprintf(__('%s or greater'), $recommended_memory) ).'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.MEMORY_LIMIT'); } if (preg_match('/system/', $PHPdisable_functions) || preg_match('/exec/', $PHPdisable_functions)) { $url = 'http://php.net/manual/en/ini.core.php#ini.disable-functions'; if ($config['language'] == 'es') { $url = 'http://php.net/manual/es/ini.core.php#ini.disable-functions'; } $this->notify( [ 'type' => 'NOTIF.PHP.DISABLE_FUNCTIONS', 'title' => __('Problems with disable_functions in php.ini'), 'message' => __('The variable disable_functions contains functions system() or exec() in PHP configuration file (php.ini)').'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator (Dont forget restart apache process after changes)'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.DISABLE_FUNCTIONS'); } if (!isset($result_ejecution) || $result_ejecution == '') { $url = 'https://www.chromium.org/getting-involved/download-chromium/'; // if ($config['language'] == 'es') { // $url = 'https://pandorafms.com/manual/es/documentation/02_installation/04_configuration#Phantomjs'; // } $this->notify( [ 'type' => 'NOTIF.PHP.CHROMIUM', 'title' => __('chromium is not installed'), 'message' => __('To be able to create images of the graphs for PDFs, please install the chromium extension. For that, it is necessary to follow these steps:'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.CHROMIUM'); } if ($php_version_array[0] < 8) { $url = 'https://pandorafms.com/manual/en/documentation/07_technical_annexes/18_php_8'; if ($config['language'] == 'es') { $url = 'https://pandorafms.com/manual/es/documentation/07_technical_annexes/18_php_8'; } if ($config['language'] == 'ja') { $url = 'https://pandorafms.com/manual/ja/documentation/07_technical_annexes/18_php_8'; } $this->notify( [ 'type' => 'NOTIF.PHP.VERSION', 'title' => __('PHP UPDATE REQUIRED'), 'message' => __('For a correct operation of PandoraFMS, PHP must be updated to version 8.0 or higher.').'
'.__('Otherwise, functionalities will be lost.').'
'."
  1. ".__('Report download in PDF format').'
  2. '."
  3. ".__('Emails Sending').'
  4. '.__('Metaconsole Collections').'
  5. ...
', 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.VERSION'); } if ($PHPSerialize_precision != -1) { $url = 'https://www.php.net/manual/en/ini.core.php#ini.serialize-precision'; if ($config['language'] == 'es') { $url = 'https://www.php.net/manual/es/ini.core.php#ini.serialize-precision'; } $this->notify( [ 'type' => 'NOTIF.PHP.SERIALIZE_PRECISION', 'title' => sprintf( __("Not recommended '%s' value in PHP configuration"), 'serialize_precision' ), 'message' => sprintf( __('Recommended value is: %s'), sprintf('-1') ).'

'.__('Please, change it on your PHP configuration file (php.ini) or contact with administrator'), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.SERIALIZE_PRECISION'); } // If PHP_VERSION is lower than 8.0.27 version_compare() returns 1. if (version_compare('8.0.27', PHP_VERSION) === 1) { $url = 'https://www.php.net/supported-versions.php'; $this->notify( [ 'type' => 'NOTIF.PHP.VERSION.SUPPORT', 'title' => __('PHP UPDATE REQUIRED'), 'message' => __('You should update your PHP version because it will be out of official support').'
'.__('Current PHP version: ').PHP_VERSION, 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.PHP.VERSION.SUPPORT'); } } /** * Checks if MYSQL version is supported. * * @return void */ public function checkMYSQLSettings() { global $config; $mysql_version = $config['dbconnection']->server_info; if (version_compare('8.0', $mysql_version) >= 0) { $url = 'https://www.mysql.com/support/eol-notice.html'; $this->notify( [ 'type' => 'NOTIF.MYSQL.VERSION', 'title' => __('MYSQL UPDATE REQUIRED'), 'message' => __('You should update your MYSQL version because it will be out of official support').'
'.__('Current MYSQL version: ').$mysql_version, 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.MYSQL.VERSION'); } } /** * Checks if history DB is available. * * @return void */ public function checkPandoraHistoryDB() { global $config; if (isset($config['history_db_enabled']) && $config['history_db_enabled'] == 1 ) { if (! isset($config['history_db_connection']) || $config['history_db_connection'] === false ) { ob_start(); $config['history_db_connection'] = db_connect( $config['history_db_host'], $config['history_db_name'], $config['history_db_user'], io_output_password($config['history_db_pass']), $config['history_db_port'], false ); ob_get_clean(); } if ($config['history_db_connection'] === false) { $this->notify( [ 'type' => 'NOTIF.HISTORYDB', 'title' => __('Historical database not available'), 'message' => __('Historical database is enabled, though not accessible with the current configuration.'), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=hist_db', ] ); } else { $this->cleanNotifications('NOTIF.HISTORYDB'); } } else { $this->cleanNotifications('NOTIF.HISTORYDB'); } } /** * Check if pandora_db is running in all available DB instances. * Generating notifications. * * @return void */ public function checkPandoraDBMaintenance() { global $config; // Main DB db_maintenance value. $db_maintance = db_get_value( 'value', 'tconfig', 'token', 'db_maintance' ); // If never was executed, it means we are in the first Pandora FMS execution. Set current timestamp. if (empty($db_maintance)) { config_update_value('db_maintance', date('U')); } $last_maintance = (date('U') - $db_maintance); // Limit 48h. if ($last_maintance > 172800) { $this->notify( [ 'type' => 'NOTIF.PANDORADB', 'title' => __('Database maintenance problem'), 'message' => __( 'Your database hasn\'t been through maintenance for 48hrs. Please, check documentation on how to perform this maintenance process on %s and enable it as soon as possible.', io_safe_output(get_product_name()) ), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } else { $this->cleanNotifications('NOTIF.PANDORADB'); } if (isset($config['history_db_enabled']) && $config['history_db_enabled'] == 1 ) { // History DB db_maintenance value. $db_maintenance = db_get_value( 'value', 'tconfig', 'token', 'db_maintenance', true ); // History db connection is supossed to be enabled since we use // db_get_value, wich initializes target db connection. if (empty($db_maintance)) { $sql = sprintf( 'UPDATE tconfig SET `value`=%d WHERE `token`="%s"', date('U'), 'db_maintenance' ); $affected_rows = db_process_sql( $sql, $rettype = 'affected_rows', $dbconnection = $config['history_db_connection'] ); if ($affected_rows == 0) { // Failed to update. Maybe the row does not exist? $sql = sprintf( 'INSERT INTO tconfig(`token`,`value`) VALUES("%s",%d)', 'db_maintenance', date('U') ); $affected_rows = db_process_sql( $sql, $rettype = 'affected_rows', $dbconnection = $config['history_db_connection'] ); } } $last_maintance = (date('U') - $db_maintance); // Limit 48h. if ($last_maintance > 172800) { $this->notify( [ 'type' => 'NOTIF.PANDORADB.HISTORY', 'title' => __( 'Historical database maintenance problem.' ), 'message' => __('Your historical database hasn\'t been through maintenance for 48hrs. Please, check documentation on how to perform this maintenance process on %s and enable it as soon as possible.', get_product_name()), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=perf', ] ); } else { // Historical db working fine. $this->cleanNotifications('NOTIF.PANDORADB.HISTORY'); } } else { // Disabled historical db. $this->cleanNotifications('NOTIF.PANDORADB.HISTORY'); } } /** * Check MR package applied in historical DB * * @return void */ public function checkPandoraHistoryDBMR() { global $config; if (isset($config['history_db_enabled']) && $config['history_db_enabled'] == 1 ) { $mrh_version = db_get_value( 'value', 'tconfig', 'token', 'MR', true ); if ($mrh_version != $config['MR']) { $this->notify( [ 'type' => 'NOTIF.HISTORYDB.MR', 'title' => __('Historical database MR mismatch'), 'message' => __('Your historical database is not using the same schema as the main DB. This could produce anomalies while storing historical data.'), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=hist_db', ] ); } else { // MR version OK. $this->cleanNotifications('NOTIF.HISTORYDB.MR'); } } else { // Disabled historical db. $this->cleanNotifications('NOTIF.HISTORYDB.MR'); } } /** * Check if elasticsearch is available. * * @return void */ public function checkExternalComponents() { global $config; // Cannot check selenium, configuration is only available from server. if (isset($config['log_collector']) && $config['log_collector'] == 1 ) { $elasticsearch = @fsockopen( $config['elasticsearch_ip'], $config['elasticsearch_port'], $errno, $errstr, 5 ); if ($elasticsearch === false) { $this->notify( [ 'type' => 'NOTIF.EXT.ELASTICSEARCH', 'title' => __('Log collector cannot connect to OpenSearch'), 'message' => __('OpenSearch is not available using current configuration.'), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=log', ] ); } else { fclose($elasticsearch); $this->cleanNotifications('NOTIF.EXT.ELASTICSEARCH'); } } else { $this->cleanNotifications('NOTIF.EXT.ELASTICSEARCH'); } } /** * Checks if metaconsole DB connection is ready. * * @return void */ public function checkMetaconsole() { global $config; $check_ok = true; if (license_free() && is_metaconsole() === false && isset($config['node_metaconsole']) && $config['node_metaconsole'] == 1 ) { // Check if node is successfully registered in MC. $server_name = db_get_value( 'distinct(name)', 'tserver', 'server_type', 1 ); $mc_db_conn = enterprise_hook( 'metaconsole_load_external_db', [ [ 'dbhost' => $config['replication_dbhost'], 'dbuser' => $config['replication_dbuser'], 'dbpass' => io_output_password( $config['replication_dbpass'] ), 'dbname' => $config['replication_dbname'], ], ] ); if ($mc_db_conn === NOERR) { $check_ok = true; } else { $check_ok = false; } // Restore the default connection. enterprise_hook('metaconsole_restore_db'); } if ($check_ok === true) { $this->cleanNotifications('NOTIF.METACONSOLE.DB_CONNECTION'); } else { $this->notify( [ 'type' => 'NOTIF.METACONSOLE.DB_CONNECTION', 'title' => __('Metaconsole DB is not available.'), 'message' => __('Cannot connect with Metaconsole DB using current configuration.'), 'url' => '__url__/index.php?sec=general&sec2=godmode/setup/setup§ion=enterprise', ] ); } } /** * Check if there are any incoming scheduled downtime in less than 15d. * * @return void */ public function checkDowntimes() { // 15 Days. $THRESHOLD_SECONDS = (15 * 3600 * 24); // Check first if any planned runtime is running. $currently_running = (int) db_get_value_sql( 'SELECT count(*) as "n" FROM tplanned_downtime WHERE executed = 1' ); if ($currently_running > 0) { $this->notify( [ 'type' => 'NOTIF.DOWNTIME', 'title' => __('Scheduled downtime running.'), 'message' => __('A scheduled downtime is running. Some monitoring data won\'t be available while downtime is taking place.'), 'url' => '__url__/index.php?sec=gagente&sec2=godmode/agentes/planned_downtime.list', ] ); return; } else { // Retrieve downtimes. $downtimes = db_get_all_rows_sql( 'SELECT * FROM tplanned_downtime WHERE (type_execution="once" AND date_from > now()) OR type_execution!="once" ORDER BY `id` DESC' ); // Initialize searchers. $next_downtime_begin = PHP_INT_MAX; $now = time(); if ($downtimes === false) { $this->cleanNotifications('NOTIF.DOWNTIME'); return; } $weekdays = [ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', ]; foreach ($downtimes as $dt) { if ($dt['type_execution'] == 'once' && ($dt['date_from'] - $now) < $THRESHOLD_SECONDS ) { if ($next_downtime_begin > $dt['date_from']) { // Store datetime for next downtime. $next_downtime_begin = $dt['date_from']; $next_downtime_end = $dt['date_to']; } } else if ($dt['type_periodicity'] == 'monthly') { $schd_time_begin = explode( ':', $dt['periodically_time_from'] ); $schd_time_end = explode( ':', $dt['periodically_time_to'] ); $begin = mktime( // Hour. $schd_time_begin[0], // Minute. $schd_time_begin[1], // Second. $schd_time_begin[2], // Month. date('n', $now), // Day. $dt['periodically_day_from'], // Year. date('Y', $now) ); $end = mktime( // Hour. $schd_time_end[0], // Minute. $schd_time_end[1], // Second. $schd_time_end[2], // Month. date('n', $now), // Day. $dt['periodically_day_to'], // Year. date('Y', $now) ); if ($next_downtime_begin > $begin) { $next_downtime_begin = $begin; $next_downtime_end = $end; } } else if ($dt['type_periodicity'] == 'weekly') { // Always applies. $current_week_day = date('N', $now); $schd_time_begin = explode( ':', $dt['periodically_time_from'] ); $schd_time_end = explode( ':', $dt['periodically_time_to'] ); $i = 0; $max = 7; while ($dt[$weekdays[(($current_week_day + $i) % 7)]] != 1 && $max-- >= 0 ) { // Calculate day of the week matching downtime // definition. $i++; } if ($max < 0) { // No days set. continue; } // Calculate utimestamp. $begin = mktime( // Hour. $schd_time_begin[0], // Minute. $schd_time_begin[1], // Second. $schd_time_begin[2], // Month. date('n', $now), // Day. (date('j', $now) + $i + 1), // Year. date('Y', $now) ); $end = mktime( // Hour. $schd_time_end[0], // Minute. $schd_time_end[1], // Second. $schd_time_end[2], // Month. date('n', $now), // Day. (date('j', $now) + $i + 1), // Year. date('Y', $now) ); if ($next_downtime_begin > $begin) { $next_downtime_begin = $begin; $next_downtime_end = $end; } } } if ($next_downtime_begin != PHP_INT_MAX) { $this->notify( [ 'type' => 'NOTIF.DOWNTIME', 'title' => __('Downtime scheduled soon.'), 'message' => __( 'A scheduled downtime is going to be executed from %s to %s. Some monitoring data won\'t be available while downtime is taking place.', date('M j, G:i:s ', $next_downtime_begin), date('M j, G:i:s ', $next_downtime_end) ), 'url' => '__url__/index.php?sec=gagente&sec2=godmode/agentes/planned_downtime.list', ] ); return; } else { $this->cleanNotifications('NOTIF.DOWNTIME'); } } } /** * Check if current instance of Pandora FMS is registered in Update Manager. * * @return void */ public function checkUpdateManagerRegistration() { global $config; include_once $config['homedir'].'/include/functions_update_manager.php'; $login = get_parameter('login', false); if (update_manager_verify_registration() === false) { $this->notify( [ 'type' => 'NOTIF.UPDATEMANAGER.REGISTRATION', 'title' => __('This instance is not registered in the Update manager section'), 'message' => __('Click here to start the registration process'), 'url' => '__url__/index.php?sec=messages&sec2=godmode/update_manager/update_manager&tab=online', ] ); } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.REGISTRATION'); } } /** * Check if has access to the API * * @return void */ public function checkApiAccess() { global $config; include_once $config['homedir'].'/include/functions_update_manager.php'; if (update_manager_verify_api() === false) { $this->notify( [ 'type' => 'NOTIF.API.ACCESS', 'title' => __('Cannot access the Pandora FMS API '), 'message' => __('Please check the configuration, some components may fail due to this misconfiguration.'), ] ); } else { $this->cleanNotifications('NOTIF.API.ACCESS'); } } /** * Check if user 'admin' is enabled and using default password. * * @return void */ public function checkDefaultPassword() { global $config; // Check default password for "admin". $admin_with_default_pass = db_get_value_sql( 'SELECT count(*) FROM tusuario WHERE id_user="admin" AND (password="1da7ee7d45b96d0e1f45ee4ee23da560" OR password="$2y$10$Wv/xoxjI2VAkthJhk/PzeeGIhBKYU/K.TMgUdmW7fEP2NQkdWlB9K") AND is_admin=1 and disabled!=1' ); if ($admin_with_default_pass > 0) { $this->notify( [ 'type' => 'NOTIF.SECURITY.DEFAULT_PASSWORD', 'title' => __('Default password for "Admin" user has not been changed'), 'message' => __('Please, change the default password since it is a commonly reported vulnerability.'), 'url' => '__url__/index.php?sec=gusuarios&sec2=godmode/users/user_list', ] ); } else { $this->cleanNotifications('NOTIF.SECURITY.DEFAULT_PASSWORD'); } } /** * Undocumented function * * @return void */ public function checkFont() { global $config; $fontpath = io_safe_output($config['fontpath']); if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { // Windows. $fontpath = $config['homedir'].'\include\fonts\\'.$fontpath; } else { $home = str_replace('\\', '/', $config['homedir']); $fontpath = $home.'/include/fonts/'.$fontpath; } if (($fontpath == '') || (file_exists($fontpath) === false) ) { $this->notify( [ 'type' => 'NOTIF.MISC.FONTPATH', 'title' => __('Default font doesn\'t exist'), 'message' => __('Your defined font doesn\'t exist or is not defined. Please, check font parameters in your config'), 'url' => is_metaconsole() === false ? '__url__/index.php?sec=gsetup&sec2=godmode/setup/setup§ion=vis' : '__url__/index.php?sec=advanced&sec2=advanced/metasetup&tab=visual', ] ); } else { $this->cleanNotifications('NOTIF.MISC.FONTPATH'); } } /** * Checks if develop_bypass is enabbled. * * @return void */ public function checkDevelopBypass() { global $develop_bypass; if ($develop_bypass == 1) { $this->notify( [ 'type' => 'NOTIF.MISC.DEVELOPBYPASS', 'title' => __('Developer mode is enabled'), 'message' => __( 'Your %s has the "develop_bypass" mode enabled. This is a developer mode and should be disabled in a production environment. This value is located in the main index.php file', get_product_name() ), 'url' => '__url__/index.php', ] ); } else { $this->cleanNotifications('NOTIF.MISC.DEVELOPBYPASS'); } } /** * Check if event storm protection is enabled. * * @return void */ public function checkEventStormProtection() { global $config; if ($config['event_storm_protection']) { $this->notify( [ 'type' => 'NOTIF.MISC.EVENTSTORMPROTECTION', 'title' => __('Event storm protection is enabled.'), 'message' => __('Some events may get lost while this mode is enabled. The server must be restarted after altering this setting.'), 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/setup/setup§ion=general', ] ); } else { $this->cleanNotifications('NOTIF.MISC.EVENTSTORMPROTECTION'); } } /** * Check if there're new updates available. * * @return void */ public function checkUpdates() { global $config; if (isset($_SESSION['new_update'])) { if (!empty($_SESSION['return_installation_open'])) { if (!$_SESSION['return_installation_open']['return']) { foreach ($_SESSION['return_installation_open']['text'] as $message) { $this->notify( [ 'type' => 'NOTIF.UPDATEMANAGER.OPENSETUP', 'title' => __('Failed to retrieve updates, please configure utility'), 'message' => $message, 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/setup/setup§ion=general', ] ); } } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.OPENSETUP'); } } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.OPENSETUP'); } if ($_SESSION['new_update'] == 'new') { $this->notify( [ 'type' => 'NOTIF.UPDATEMANAGER.UPDATE', 'title' => __( 'New %s Console update', get_product_name() ), 'message' => __('There is a new update available. Please go to Administration:Setup:Update Manager for more details.'), 'url' => '__url__/index.php?sec=gsetup&sec2=godmode/update_manager/update_manager&tab=online', ] ); } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.UPDATE'); } } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.OPENSETUP'); $this->cleanNotifications('NOTIF.UPDATEMANAGER.UPDATE'); } } /** * Check if there're minor updates available. * * @return void */ public function checkMinorRelease() { global $config; $check_minor_release_available = db_check_minor_relase_available(); if ($check_minor_release_available) { $url = 'https://pandorafms.com/manual/es/documentation/02_installation/02_anexo_upgrade#version_70ng_rolling_release'; if ($config['language'] == 'es') { $url = 'https://pandorafms.com/manual/en/documentation/02_installation/02_anexo_upgrade#version_70ng_rolling_release'; } $this->notify( [ 'type' => 'NOTIF.UPDATEMANAGER.MINOR', 'title' => __('Minor release/s available'), 'message' => __( 'There is one or more minor releases available. .About minor release update.', $url ), 'url' => '__url__/index.php?sec=messages&sec2=godmode/update_manager/update_manager&tab=online', ] ); } else { $this->cleanNotifications('NOTIF.UPDATEMANAGER.MINOR'); } } /** * Check if CRON utility has been configured. * * @return void */ public function checkCronRunning() { global $config; // Check if DiscoveryCronTasks is running. Warn user if not. if ($config['cron_last_run'] == 0 || (get_system_time() - $config['cron_last_run']) > SECONDS_10MINUTES ) { $message_conf_cron = __('DiscoveryConsoleTasks is not running properly'); if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') { $message_conf_cron .= __('Discovery relies on an appropriate cron setup.'); $message_conf_cron .= '. '.__('Please, add the following line to your crontab file:'); $message_conf_cron .= '
* * * * * <user> wget -q -O - --no-check-certificate --load-cookies /tmp/cron-session-cookies --save-cookies /tmp/cron-session-cookies --keep-session-cookies ';
                $message_conf_cron .= str_replace(
                    ENTERPRISE_DIR.'/meta/',
                    '',
                    ui_get_full_url(false)
                );
                $message_conf_cron .= ENTERPRISE_DIR.'/'.EXTENSIONS_DIR;
                $message_conf_cron .= '/cron/cron.php >> 
'; $message_conf_cron .= $config['homedir'].'/log/cron.log'; } if (isset($config['cron_last_run']) === true) { $message_conf_cron .= __('Last execution').': '; $message_conf_cron .= date('Y/m/d H:i:s', $config['cron_last_run']); $message_conf_cron .= __('Please, make sure process is not locked.'); } $url = '__url__/index.php?sec=gservers&sec2=godmode/servers/discovery&wiz=tasklist'; if (is_metaconsole() === true) { $url = '__url__index.php?sec=extensions&sec2=enterprise/extensions/cron'; } $this->notify( [ 'type' => 'NOTIF.CRON.CONFIGURED', 'title' => __('DiscoveryConsoleTasks is not configured.'), 'message' => __($message_conf_cron), 'url' => $url, ] ); } else { $this->cleanNotifications('NOTIF.CRON.CONFIGURED'); } } /** * Search for messages. * * @return void */ public function getUMMessages() { global $config; include_once $config['homedir'].'/include/functions_update_manager.php'; if (update_manager_verify_registration() === false) { // Console not subscribed. return; } // Avoid contact for messages too much often. if (isset($config['last_um_check']) === true && time() < $config['last_um_check'] ) { return; } // Only ask for messages once every 2 hours. $future = (time() + 2 * SECONDS_1HOUR); config_update_value('last_um_check', $future, true); $messages = update_manager_get_messages(); if (is_array($messages) === true) { $source_id = get_notification_source_id( 'Official communication' ); foreach ($messages as $message) { if (isset($message['url']) === false) { $message['url'] = '#'; } $this->notify( [ 'type' => 'NOTIF.UPDATEMANAGER.MESSAGES.'.$message['id'], 'title' => $message['subject'], 'message' => base64_decode($message['message_html']), 'url' => $message['url'], ], $source_id ); } } } /** * Check if all servers and console versions are the same * * @return void */ public function checkConsoleServerVersions() { global $config; // List all servers except satellite server. $server_version_list = db_get_all_rows_sql( sprintf( 'SELECT `name`, `version` FROM tserver WHERE server_type != %d GROUP BY `version`', SERVER_TYPE_ENTERPRISE_SATELLITE ) ); $missed = 0; if (is_array($server_version_list) === true) { foreach ($server_version_list as $server) { if (strpos( $server['version'], (string) floor((int) $config['current_package']) ) === false ) { $missed++; $title_ver_misaligned = __( '%s version misaligned with Console', $server['name'] ); $message_ver_misaligned = __( 'Server %s and this console have different versions. This might cause several malfunctions. Please, update this server.', $server['name'] ); $this->notify( [ 'type' => 'NOTIF.SERVER.MISALIGNED', 'title' => __($title_ver_misaligned), 'message' => __($message_ver_misaligned), 'url' => '__url__/index.php?sec=messages&sec2=godmode/update_manager/update_manager&tab=online', ] ); break; } } } // Cleanup notifications if exception is recovered. if ($missed == 0) { $this->cleanNotifications('NOTIF.SERVER.MISALIGNED'); } } /** * Check if AllowOveride is None or All. * * @return void */ public function checkAllowOverrideEnabled() { global $config; $message = 'If AllowOverride is disabled, .htaccess will not works.'; if (PHP_OS == 'FreeBSD') { $message .= '
Please check /usr/local/etc/apache24/httpd.conf to resolve this problem.';
        } else {
            $message .= '
Please check /etc/httpd/conf/httpd.conf to resolve this problem.';
        }

        // Get content file.
        if (PHP_OS == 'FreeBSD') {
            $file = file_get_contents('/usr/local/etc/apache24/httpd.conf');
        } else {
            $file = file_get_contents('/etc/httpd/conf/httpd.conf');
        }

        $file_lines = preg_split("#\r?\n#", $file, -1, PREG_SPLIT_NO_EMPTY);
        $is_none = false;

        $i = 0;
        foreach ($file_lines as $line) {
            $i++;

            // Check Line and content.
            if (preg_match('/ AllowOverride/', $line) && $i === 311) {
                $result = explode(' ', $line);
                if ($result[5] == 'None') {
                    $is_none = true;
                    $this->notify(
                        [
                            'type'    => 'NOTIF.ALLOWOVERRIDE.MESSAGE',
                            'title'   => __('AllowOverride is disabled'),
                            'message' => __($message),
                            'url'     => '__url__/index.php',
                        ]
                    );
                }
            }
        }

        // Cleanup notifications if AllowOverride is All.
        if (!$is_none) {
            $this->cleanNotifications('NOTIF.ALLOWOVERRIDE.MESSAGE');
        }

    }


    /**
     * Check if AllowOveride is None or All.
     *
     * @return void
     */
    public function checkHaStatus()
    {
        global $config;
        enterprise_include_once('include/class/DatabaseHA.class.php');

        $cluster = new DatabaseHA();
        $nodes = $cluster->getNodes();

        foreach ($nodes as $node) {
            if ($node['status'] == HA_DISABLED) {
                continue;
            }

            $cluster_master = $cluster->isClusterMaster($node);
            $db_master = $cluster->isDBMaster($node);

            $message = '
The roles played by node '.$node['host'].' are out of sync:
            Role in the cluster: Master
            Role in the database: Slave Desynchronized operation in the node';

            if ((int) $db_master !== (int) $cluster_master) {
                $this->notify(
                    [
                        'type'    => 'NOTIF.HAMASTER.MESSAGE',
                        'title'   => __('Desynchronized operation on the node '.$node['host']),
                        'message' => __($message),
                        'url'     => '__url__/index.php?sec=gservers&sec2=enterprise/godmode/servers/HA_cluster',
                    ]
                );
            } else {
                $this->cleanNotifications('NOTIF.HAMASTER.MESSAGE');
            }
        }
    }


    /**
     * Check if Pandora console log file remains in old location.
     *
     * @return void
     */
    public function checkPandoraConsoleLogOldLocation()
    {
        global $config;

        if (file_exists($config['homedir'].'/pandora_console.log')) {
            $title_pandoraconsole_old_log = __(
                'Pandora FMS console log file changed location',
                $config['homedir']
            );
            $message_pandoraconsole_old_log = __(
                'Pandora FMS console log file has been moved to new location %s/log. Currently you have an outdated and inoperative version of this file at %s. Please, consider deleting it.',
                $config['homedir'],
                $config['homedir']
            );

            $url = 'https://pandorafms.com/manual/en/quickguides/general_quick_guide#solving_problems_where_to_look_and_who_to_ask';
            if ($config['language'] == 'es') {
                $url = 'https://pandorafms.com//manual/es/quickguides/general_quick_guide#solucion_de_problemas_donde_mirar_a_quien_preguntar';
            }

            $this->notify(
                [
                    'type'    => 'NOTIF.PANDORACONSOLE.LOG.OLD',
                    'title'   => __($title_pandoraconsole_old_log),
                    'message' => __($message_pandoraconsole_old_log),
                    'url'     => $url,
                ]
            );
        } else {
            $this->cleanNotifications('NOTIF.PANDORACONSOLE.LOG.OLD');
        }
    }


    /**
     * Check if audit log file remains in old location.
     *
     * @return void
     */
    public function checkAuditLogOldLocation()
    {
        global $config;

        if (file_exists($config['homedir'].'/audit.log')) {
            $title_audit_old_log = __(
                'Pandora FMS audit log file changed location',
                $config['homedir']
            );
            $message_audit_old_log = __(
                'Pandora FMS audit log file has been moved to new location %s/log. Currently you have an outdated and inoperative version of this file at %s. Please, consider deleting it.',
                $config['homedir'],
                $config['homedir']
            );

            $this->notify(
                [
                    'type'    => 'NOTIF.AUDIT.LOG.OLD',
                    'title'   => __($title_audit_old_log),
                    'message' => __($message_audit_old_log),
                    'url'     => '#',
                ]
            );
        } else {
            $this->cleanNotifications('NOTIF.AUDIT.LOG.OLD');
        }
    }


    /**
     * Verifies the status of synchronization queue and warns if something is
     * not working as expected.
     *
     * @return void
     */
    public function checkSyncQueueLength()
    {
        global $config;

        if (is_metaconsole() !== true) {
            return;
        }

        $sync = new PandoraFMS\Enterprise\Metaconsole\Synchronizer(true);
        $counts = $sync->getQueues(true);

        if (count($counts) === 0) {
            // Clean all.
            $this->cleanNotifications('NOTIF.SYNCQUEUE.LENGTH.%');
        }

        $items_min = (isset($config['sync_queue_items_max']) === true) ? $config['sync_queue_items_max'] : 0;
        if (is_numeric($items_min) !== true && $items_min <= 0) {
            $items_min = self::MIN_SYNC_QUEUE_LENGTH;
        }

        foreach ($counts as $node_id => $count) {
            if ($count < $items_min) {
                $this->cleanNotifications('NOTIF.SYNCQUEUE.LENGTH.'.$node_id);
            } else {
                try {
                    $node = new PandoraFMS\Enterprise\Metaconsole\Node($node_id);

                    $url = '__url__/index.php?sec=advanced&sec2=advanced/metasetup&tab=consoles';

                    $this->notify(
                        [
                            'type'    => 'NOTIF.SYNCQUEUE.LENGTH.'.$node_id,
                            'title'   => __('Node %s sync queue length exceeded, ', $node->server_name()),
                            'message' => __(
                                'Synchronization queue lenght for node %s is %d items, this value should be 0 or lower than %d, please check the queue status.',
                                $node->server_name(),
                                $count,
                                $items_min
                            ),
                            'url'     => $url,
                        ]
                    );
                } catch (\Exception $e) {
                    // Clean, exception in node finding.
                    $this->cleanNotifications('NOTIF.SYNCQUEUE.LENGTH.'.$node_id);
                }
            }
        }

    }


    /**
     * Verifies the status of synchronization queue and warns if something is
     * not working as expected.
     *
     * @return void
     */
    public function checkSyncQueueStatus()
    {
        if (is_metaconsole() !== true) {
            return;
        }

        $sync = new PandoraFMS\Enterprise\Metaconsole\Synchronizer(true);
        $queues = $sync->getQueues();
        if (count($queues) === 0) {
            // Clean all.
            $this->cleanNotifications('NOTIF.SYNCQUEUE.STATUS.%');
        }

        foreach ($queues as $node_id => $queue) {
            if (count($queue) === 0) {
                $this->cleanNotifications('NOTIF.SYNCQUEUE.STATUS.'.$node_id);
                continue;
            }

            $item = $queue[0];

            if (empty($item->error()) === false) {
                try {
                    $node = new PandoraFMS\Enterprise\Metaconsole\Node($node_id);
                    $url = '__url__/index.php?sec=advanced&sec2=advanced/metasetup&tab=consoles';

                    $this->notify(
                        [
                            'type'    => 'NOTIF.SYNCQUEUE.STATUS.'.$node_id,
                            'title'   => __('Node %s sync queue failed, ', $node->server_name()),
                            'message' => __(
                                'Node %s cannot process synchronization queue due %s, please check the queue status.',
                                $node->server_name(),
                                $item->error()
                            ),
                            'url'     => $url,
                        ]
                    );
                } catch (\Exception $e) {
                    // Clean, exception in node finding.
                    $this->cleanNotifications('NOTIF.SYNCQUEUE.STATUS.'.$node_id);
                }
            }
        }

    }


    /**
     * Chechs if an agent has a dependency eror on omnishell
     *
     * @return void
     */
    public function checkLibaryError()
    {
        $sql = 'SELECT COUNT(errorlevel) from tremote_command_target WHERE errorlevel = 2';

        $error_dependecies = db_get_sql($sql);
        if ($error_dependecies > 0) {
            $this->notify(
                [
                    'type'    => 'NOTIF.AGENT.LIBRARY',
                    'title'   => __('Agent dependency error'),
                    'message' => __(
                        'There are omnishell agents with dependency errors',
                    ),

                    'url'     => '__url__/index.php?sec=gextensions&sec2=enterprise/tools/omnishell',
                ]
            );
        }
    }


}