1<?php
2/*
3 +-------------------------------------------------------------------------+
4 | Copyright (C) 2004-2021 The Cacti Group                                 |
5 |                                                                         |
6 | This program is free software; you can redistribute it and/or           |
7 | modify it under the terms of the GNU General Public License             |
8 | as published by the Free Software Foundation; either version 2          |
9 | of the License, or (at your option) any later version.                  |
10 |                                                                         |
11 | This program is distributed in the hope that it will be useful,         |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of          |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           |
14 | GNU General Public License for more details.                            |
15 +-------------------------------------------------------------------------+
16 | Cacti: The Complete RRDtool-based Graphing Solution                     |
17 +-------------------------------------------------------------------------+
18 | This code is designed, written, and maintained by the Cacti Group. See  |
19 | about.php and/or the AUTHORS file for specific developer information.   |
20 +-------------------------------------------------------------------------+
21 | http://www.cacti.net/                                                   |
22 +-------------------------------------------------------------------------+
23*/
24
25/*
26   !!! IMPORTANT !!!
27
28   The following defaults are not to be altered.  Please refer to
29   include/config.php for user configurable settings.
30
31*/
32
33/* load cacti version from file */
34$cacti_version_file = dirname(__FILE__) . '/cacti_version';
35
36if (! file_exists($cacti_version_file)) {
37	die ('ERROR: failed to find cacti version file');
38}
39
40$cacti_version = file_get_contents($cacti_version_file, false);
41if ($cacti_version === false) {
42	die ('ERROR: failed to load cacti version file');
43}
44$cacti_version = trim($cacti_version);
45
46/* define cacti version */
47define('CACTI_VERSION', $cacti_version);
48#define('CACTI_VERSION_BETA', 1);
49
50/* define if cacti is in CLI mode */
51define('CACTI_CLI', (php_sapi_name() == 'cli'));
52if (defined('CACTI_CLI_ONLY') && !CACTI_CLI) {
53	die('<br><strong>This script is only meant to run at the command line.</strong>');
54}
55
56// define documentation table of contents
57define('CACTI_DOCUMENTATION_TOC', 'docs/Table-of-Contents.html');
58
59/* Default database settings*/
60$database_type     = 'mysql';
61$database_default  = 'cacti';
62$database_hostname = 'localhost';
63$database_username = 'cactiuser';
64$database_password = 'cactiuser';
65$database_port     = '3306';
66$database_retries  = 2;
67
68$database_ssl      = false;
69$database_ssl_key  = '';
70$database_ssl_cert = '';
71$database_ssl_ca   = '';
72$database_persist  = true;
73
74/* Default session name - Session name must contain alpha characters */
75$cacti_session_name = 'Cacti';
76
77/* define default url path */
78$url_path = '/cacti/';
79
80/* disable log rotation setting */
81$disable_log_rotation = false;
82
83$config = array();
84
85/* Include configuration, or use the defaults */
86if (file_exists(dirname(__FILE__) . '/config.php')) {
87	if (!is_readable(dirname(__FILE__) . '/config.php')) {
88		die('Configuration file include/config.php is present, but unreadable.' . PHP_EOL);
89	}
90	include(dirname(__FILE__) . '/config.php');
91}
92
93if (isset($config['cacti_version'])) {
94	die('Invalid include/config.php file detected.' . PHP_EOL);
95	exit;
96}
97
98/* Set the poller_id */
99if (isset($poller_id)) {
100	$config['poller_id'] = $poller_id;
101} else {
102	$config['poller_id'] = 1;
103}
104
105$db_var_defaults = array(
106	'database_type'     => 'mysql',
107	'database_default'  => NULL,
108	'database_hostname' => NULL,
109	'database_username' => NULL,
110	'database_password' => NULL,
111	'database_port'     => '3306',
112	'database_retries'  => 2,
113	'database_ssl'      => false,
114	'database_ssl_key'  => '',
115	'database_ssl_cert' => '',
116	'database_ssl_ca'   => '',
117);
118
119$db_var_prefixes = array('');
120if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
121	$db_var_prefixes[] = 'r';
122}
123
124$db_missing_vars = '';
125foreach ($db_var_prefixes as $db_var_prefix) {
126	foreach ($db_var_defaults as $db_var_name => $db_var_default) {
127		$db_var_full = $db_var_prefix . $db_var_name;
128		if (!isset($$db_var_full)) {
129			if ($db_var_default !== NULL) {
130				$$db_var_full = $db_var_default;
131			} else {
132				$db_missing_vars .= (($db_missing_vars == '') ? 'missing ' : ', ') . $db_var_full;
133			}
134		}
135	}
136}
137
138if (!empty($db_missing_vars)) {
139	die("config.php is $db_missing_vars" . PHP_EOL);
140}
141
142if (empty($url_path)) {
143	/* define default url path */
144	$url_path = '/';
145}
146
147/* set the local for international users */
148setlocale(LC_CTYPE, 'en_US.UTF-8');
149
150/* Files that do not need http header information - Command line scripts */
151$no_http_header_files = array(
152	'add_device.php',
153	'add_graphs.php',
154	'add_perms.php',
155	'add_tree.php',
156	'boost_rrdupdate.php',
157	'cmd.php',
158	'cmd_realtime.php',
159	'copy_user.php',
160	'host_update_template.php',
161	'poller_automation.php',
162	'poller_boost.php',
163	'poller_commands.php',
164	'poller_dsstats.php',
165	'poller_export.php',
166	'poller_graphs_reapply_names.php',
167	'poller_maintenance.php',
168	'poller_output_empty.php',
169	'poller.php',
170	'poller_realtime.php',
171	'poller_recovery.php',
172	'poller_reindex_hosts.php',
173	'poller_reports.php',
174	'poller_spikekill.php',
175	'query_host_cpu.php',
176	'query_host_partitions.php',
177	'rebuild_poller_cache.php',
178	'repair_database.php',
179	'script_server.php',
180	'snmpagent_mibcachechild.php',
181	'snmpagent_mibcache.php',
182	'snmpagent_persist.php',
183	'sql.php',
184	'ss_host_cpu.php',
185	'ss_host_disk.php',
186	'ss_sql.php',
187	'structure_rra_paths.php',
188);
189
190$colors = array();
191
192/* this should be auto-detected, set it manually if needed */
193$config['cacti_server_os'] = (strstr(PHP_OS, 'WIN')) ? 'win32' : 'unix';
194
195if (!empty($path_csrf_secret)) {
196	$config['path_csrf_secret'] = $path_csrf_secret;
197}
198
199/* built-in snmp support */
200if (isset($php_snmp_support) && !$php_snmp_support) {
201	$config['php_snmp_support'] = false;
202} else {
203	$config['php_snmp_support'] = class_exists('SNMP');
204}
205
206/* PHP binary location */
207if (isset($php_path)) {
208	$config['php_path'] = $php_path;
209}
210
211/* Set various debug fields */
212$config['DEBUG_READ_CONFIG_OPTION']         = defined('DEBUG_READ_CONFIG_OPTION');
213$config['DEBUG_READ_CONFIG_OPTION_DB_OPEN'] = defined('DEBUG_READ_CONFIG_OPTION_DB_OPEN');
214$config['DEBUG_SQL_CMD']                    = defined('DEBUG_SQL_CMD');
215$config['DEBUG_SQL_FLOW']                   = defined('DEBUG_SQL_FLOW');
216
217/* check for an empty database port */
218if (empty($database_port)) {
219	$database_port = '3306';
220}
221
222/* set URL path */
223if (!isset($url_path)) {
224	$url_path = '';
225}
226$config['url_path'] = $url_path;
227define('URL_PATH', $url_path);
228
229/* used for includes */
230if ($config['cacti_server_os'] == 'win32') {
231	$config['base_path']    = str_replace("\\", "/", substr(dirname(__FILE__),0,-8));
232	$config['library_path'] = $config['base_path'] . '/lib';
233} else {
234	$config['base_path']    = preg_replace("/(.*)[\/]include/", "\\1", dirname(__FILE__));
235	$config['library_path'] = preg_replace("/(.*[\/])include/", "\\1lib", dirname(__FILE__));
236}
237$config['include_path'] = dirname(__FILE__);
238$config['rra_path'] = '/var/db/cacti/rra';
239
240/* for multiple pollers, we need to know this location */
241if (!isset($scripts_path)) {
242	$config['scripts_path'] = $config['base_path'] . '/scripts';
243} else {
244	$config['scripts_path'] = $scripts_path;
245}
246
247if (!isset($resource_path)) {
248	$config['resource_path'] = $config['base_path'] . '/resource';
249} else {
250	$config['resource_path'] = $resource_path;
251}
252
253if (isset($input_whitelist)) {
254	$config['input_whitelist'] = $input_whitelist;
255}
256
257/* include base modules */
258include_once($config['library_path'] . '/database.php');
259include_once($config['library_path'] . '/functions.php');
260include_once($config['include_path'] . '/global_constants.php');
261include_once($config['library_path'] . '/html.php');
262include_once($config['library_path'] . '/html_utility.php');
263include_once($config['library_path'] . '/html_validate.php');
264
265$filename = get_current_page();
266
267$config['is_web'] = !defined('CACTI_CLI_ONLY');
268if ((isset($no_http_headers) && $no_http_headers == true) || in_array($filename, $no_http_header_files, true)) {
269	$config['is_web'] = false;
270}
271
272/* set poller mode */
273global $local_db_cnn_id, $remote_db_cnn_id;
274
275$config['connection'] = 'online';
276
277if ($config['poller_id'] > 1 || isset($rdatabase_hostname)) {
278	$local_db_cnn_id = db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca);
279
280	if (!isset($rdatabase_retries))  $rdatabase_retries  = 2;
281	if (!isset($rdatabase_ssl))      $rdatabase_ssl      = false;
282	if (!isset($rdatabase_ssl_key))  $rdatabase_ssl_key  = false;
283	if (!isset($rdatabase_ssl_cert)) $rdatabase_ssl_cert = false;
284	if (!isset($rdatabase_ssl_ca))   $rdatabase_ssl_ca   = false;
285
286	// Check for recovery
287	if (is_object($local_db_cnn_id)) {
288		$boost_records = db_fetch_cell('SELECT COUNT(*)
289			FROM poller_output_boost', '', true, $local_db_cnn_id);
290
291		if ($boost_records > 0) {
292			$config['connection'] = 'recovery';
293		}
294	}
295
296	/* gather the existing cactidb version */
297	$config['cacti_db_version'] = db_fetch_cell('SELECT cacti FROM version LIMIT 1', false, $local_db_cnn_id);
298
299	// We are a remote poller also try to connect to the remote database
300	$remote_db_cnn_id = db_connect_real($rdatabase_hostname, $rdatabase_username, $rdatabase_password, $rdatabase_default, $rdatabase_type, $rdatabase_port, $database_retries, $rdatabase_ssl, $rdatabase_ssl_key, $rdatabase_ssl_cert, $rdatabase_ssl_ca);
301
302	if ($config['is_web'] && is_object($remote_db_cnn_id) &&
303		$config['connection'] != 'recovery' &&
304		$config['cacti_db_version'] != 'new_install') {
305
306		// Connection worked, so now override the default settings so that it will always utilize the remote connection
307		$database_default   = $rdatabase_default;
308		$database_hostname  = $rdatabase_hostname;
309		$database_username  = $rdatabase_username;
310		$database_password  = $rdatabase_password;
311		$database_port      = $rdatabase_port;
312		$database_ssl       = $rdatabase_ssl;
313		$database_ssl_key   = $rdatabase_ssl_key;
314		$database_ssl_cert  = $rdatabase_ssl_cert;
315		$database_ssl_ca    = $rdatabase_ssl_ca;
316	} elseif (is_object($remote_db_cnn_id)) {
317		if ($config['connection'] != 'recovery') {
318			$config['connection'] = 'online';
319		}
320	} else {
321		$config['connection'] = 'offline';
322	}
323} else {
324	if (!isset($database_ssl))      $database_ssl      = false;
325	if (!isset($database_ssl_key))  $database_ssl_key  = false;
326	if (!isset($database_ssl_cert)) $database_ssl_cert = false;
327	if (!isset($database_ssl_ca))   $database_ssl_ca   = false;
328
329	if (!db_connect_real($database_hostname, $database_username, $database_password, $database_default, $database_type, $database_port, $database_retries, $database_ssl, $database_ssl_key, $database_ssl_cert, $database_ssl_ca)) {
330		$ps = $config['is_web'] ? '<p>' : '';
331		$sp = $config['is_web'] ? '</p>' : PHP_EOL;
332		$ul = $config['is_web'] ? '<ul>' : PHP_EOL;
333		$li = $config['is_web'] ? '<li>' : PHP_EOL . '  - ';
334		$lu = $config['is_web'] ? '</ul>' : '';
335		$il = $config['is_web'] ? '</li>' : '';
336		print $ps . 'FATAL: Connection to Cacti database failed. Please ensure: ' . $ul;
337		print $li . 'the PHP MySQL module is installed and enabled.' . $il;
338		print $li . 'the database is running.' . $il;
339		print $li . 'the credentials in config.php are valid.' . $il;
340		print $lu . $sp;
341		if (isset($_REQUEST['display_db_errors']) & !empty($config['DATABASE_ERROR'])) {
342			print $ps . 'The following database errors occurred: ' . $ul;
343			foreach ($config['DATABASE_ERROR'] as $e) {
344				print $li . $e['Code'] . ': ' . $e['Error'] . $il;
345			}
346			print $lu . $sp;
347		}
348		exit;
349	} else {
350		/* gather the existing cactidb version */
351		$config['cacti_db_version'] = db_fetch_cell('SELECT cacti FROM version LIMIT 1');
352	}
353}
354
355/* check cacti log is available */
356$log_filename = cacti_log_file();
357if (!is_resource_writable($log_filename)) {
358	die('System log file is not available for writing, please enable write access' . PHP_EOL . 'Log: ' . $log_filename . PHP_EOL);
359}
360
361if ($config['poller_id'] > 1) {
362	$timezone = db_fetch_cell_prepared('SELECT timezone
363		FROM poller
364		WHERE id = ?',
365		array($config['poller_id']));
366
367	if ($timezone != '') {
368		db_execute_prepared('SET time_zone = ?', array($timezone));
369	}
370}
371
372if (isset($cacti_db_session) && $cacti_db_session && db_table_exists('sessions')) {
373	include(dirname(__FILE__) . '/session.php');
374} else {
375	$cacti_db_session = false;
376}
377
378if (!defined('IN_CACTI_INSTALL')) {
379	set_error_handler('CactiErrorHandler');
380	register_shutdown_function('CactiShutdownHandler');
381}
382
383/* verify the cacti database is initialized before moving past here */
384db_cacti_initialized($config['is_web']);
385
386if ($config['is_web']) {
387	if (read_config_option('force_https') == 'on') {
388		if (!isset($_SERVER['HTTPS']) && isset($_SERVER['HTTP_HOST']) && isset($_SERVER['REQUEST_URI'])) {
389			header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . PHP_EOL . PHP_EOL);
390			exit;
391		}
392	}
393
394	/* set the maximum post size */
395	ini_set('post_max_size', '8M');
396
397	/* add additional cookie directives */
398	ini_set('session.cookie_httponly', true);
399	ini_set('session.cookie_path', $config['url_path']);
400	ini_set('session.use_strict_mode', true);
401
402	$options = array(
403		'cookie_httponly' => true,
404		'cookie_path'     => $config['url_path'],
405		'use_strict_mode' => true
406	);
407
408	if (isset($cacti_cookie_domain) && $cacti_cookie_domain != '') {
409		ini_set('session.cookie_domain', $cacti_cookie_domain);
410		$options['cookie_domain'] = $cacti_cookie_domain;
411	}
412
413	// SameSite php7.3+ behavior
414	if (version_compare(PHP_VERSION, '7.3', '>=')) {
415		ini_set('session.cookie_samesite', 'Strict');
416		$options['cookie_samesite'] = 'Strict';
417	}
418
419	if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
420		ini_set('session.cookie_secure', true);
421		$options['cookie_secure'] = true;
422	}
423
424	$config['cookie_options']     = $options;
425	$config['cacti_session_name'] = $cacti_session_name;
426
427	/* we don't want these pages cached */
428	header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
429	header('X-Frame-Options: SAMEORIGIN');
430
431	/* increased web hardening */
432	$script_policy = read_config_option('content_security_policy_script');
433	if ($script_policy == 'unsafe-eval') {
434		$script_policy = "'$script_policy'";
435	} else {
436		$script_policy = '';
437	}
438	$alternates = html_escape(read_config_option('content_security_alternate_sources'));
439
440	header("Content-Security-Policy: default-src *; img-src 'self' $alternates data: blob:; style-src 'self' 'unsafe-inline' $alternates; script-src 'self' $script_policy 'unsafe-inline' $alternates; frame-ancestors 'self'; worker-src 'self' $alternates;");
441
442	/* prevent IE from silently rejects cookies sent from third party sites. */
443	header('P3P: CP="CAO PSA OUR"');
444	header('Cache-Control: no-store, no-cache, must-revalidate');
445	header('Cache-Control: max-age=31536000');
446
447	cacti_session_start();
448
449	/* we never run with magic quotes on */
450	if (version_compare(PHP_VERSION, '5.4', '<=')) {
451		if (get_magic_quotes_gpc()) {
452			$process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
453			foreach ($process as $key => $val) {
454				foreach ($val as $k => $v) {
455					unset($process[$key][$k]);
456					if (is_array($v)) {
457						$process[$key][stripslashes($k)] = $v;
458						$process[] = &$process[$key][stripslashes($k)];
459					} else {
460						$process[$key][stripslashes($k)] = stripslashes($v);
461					}
462				}
463			}
464			unset($process);
465		}
466	}
467
468	/* make sure to start only only Cacti session at a time */
469	if (!isset($_SESSION['cacti_cwd'])) {
470		$_SESSION['cacti_cwd'] = $config['base_path'];
471	} else {
472		if ($_SESSION['cacti_cwd'] != $config['base_path']) {
473			cacti_session_destroy();
474		}
475	}
476
477	/* Sanitize the http referer */
478	if (isset($_SERVER['HTTP_REFERER'])) {
479		$_SERVER['HTTP_REFERER'] = sanitize_uri($_SERVER['HTTP_REFERER']);
480	}
481}
482
483/* emulate 'register_globals' = 'off' if turned on */
484if ((bool)ini_get('register_globals')) {
485	$not_unset = array('_GET', '_POST', '_COOKIE', '_SERVER', '_SESSION', '_ENV', '_FILES', 'database_type', 'database_default', 'database_hostname', 'database_username', 'database_password', 'config', 'colors');
486
487	/* Not only will array_merge give a warning if a parameter is not an array, it will
488	* actually fail. So we check if HTTP_SESSION_VARS has been initialised. */
489	if (!isset($_SESSION)) {
490		$_SESSION = array();
491	}
492
493	/* Merge all into one extremely huge array; unset this later */
494	$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_SESSION, $_ENV, $_FILES);
495
496	unset($input['input']);
497	unset($input['not_unset']);
498
499	foreach ($input as $var => $val) {
500		if (!in_array($var, $not_unset)) {
501			unset($$var);
502		}
503	}
504
505	unset($input);
506}
507
508define('CACTI_DATE_TIME_FORMAT', date_time_format());
509
510include_once($config['include_path'] . '/global_languages.php');
511include_once($config['library_path'] . '/auth.php');
512include_once($config['library_path'] . '/plugins.php');
513include_once($config['include_path'] . '/plugins.php');
514include_once($config['include_path'] . '/global_arrays.php');
515include_once($config['include_path'] . '/global_settings.php');
516include_once($config['include_path'] . '/global_form.php');
517include_once($config['library_path'] . '/html_form.php');
518include_once($config['library_path'] . '/html_filter.php');
519include_once($config['library_path'] . '/variables.php');
520include_once($config['library_path'] . '/mib_cache.php');
521include_once($config['library_path'] . '/poller.php');
522include_once($config['library_path'] . '/snmpagent.php');
523include_once($config['library_path'] . '/aggregate.php');
524include_once($config['library_path'] . '/api_automation.php');
525include_once($config['include_path'] . '/csrf.php');
526
527if ($config['is_web']) {
528	if (isset_request_var('newtheme')) {
529		unset($_SESSION['selected_theme']);
530	}
531
532	if (isset_request_var('csrf_timeout')) {
533		raise_message('csrf_ptimeout');
534	}
535
536	/* check for save actions using GET */
537	if (isset_request_var('action')) {
538		$action = get_nfilter_request_var('action');
539
540		$bad_actions = array('save', 'update_data', 'changepassword');
541
542		foreach($bad_actions as $bad) {
543			if ($action == $bad && !isset($_POST['__csrf_magic'])) {
544				cacti_log('WARNING: Attempt to use GET method for POST operations from IP ' . get_client_addr(), false, 'WEBUI');
545				exit;
546			}
547		}
548	}
549
550	if (isset($_COOKIE['CactiTimeZone'])) {
551		$gmt_offset = $_COOKIE['CactiTimeZone'];
552
553		cacti_time_zone_set($gmt_offset);
554	}
555}
556
557api_plugin_hook('config_insert');
558
559/* set config cacti_version for plugins */
560$config['cacti_version'] = CACTI_VERSION;;
561
562