Project

General

Profile

Download (29.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/config
3
 * NAME
4
 *   config.lib.inc - Functions to manipulate config.xml
5
 * DESCRIPTION
6
 *   This include contains various config.xml specific functions.
7
 * HISTORY
8
 * $Id$
9
 ******
10

    
11
	config.lib.inc
12
	Ported from config.inc by Erik Kristensen
13
	Copyright (C) 2004-2010 Scott Ullrich
14
	All rights reserved.
15

    
16
	originally part of m0n0wall (http://m0n0.ch/wall)
17
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
18
	All rights reserved.
19

    
20
	Redistribution and use in source and binary forms, with or without
21
	modification, are permitted provided that the following conditions are met:
22

    
23
	1. Redistributions of source code must retain the above copyright notice,
24
	   this list of conditions and the following disclaimer.
25

    
26
	2. Redistributions in binary form must reproduce the above copyright
27
	   notice, this list of conditions and the following disclaimer in the
28
	   documentation and/or other materials provided with the distribution.
29

    
30
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
	POSSIBILITY OF SUCH DAMAGE.
40
*/
41

    
42
/****f* config/encrypted_configxml
43
 * NAME
44
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
45
 * INPUTS
46
 *   None
47
 * RESULT
48
 *   $config 	- rewrites config.xml without encryption
49
 ******/
50
function encrypted_configxml() {
51
	global $g, $config;
52

    
53
	if (!file_exists($g['conf_path'] . "/config.xml")) {
54
		return;
55
	}
56

    
57
	if (!platform_booting()) {
58
		return;
59
	}
60

    
61
	$configtxt = file_get_contents($g['conf_path'] . "/config.xml");
62
	if (tagfile_deformat($configtxt, $configtxt, "config.xml")) {
63
		$fp = fopen('php://stdin', 'r');
64
		$data = "";
65
		echo "\n\n*** Encrypted config.xml detected ***\n";
66
		while ($data == "") {
67
			echo "\nEnter the password to decrypt config.xml: ";
68
			$decrypt_password = chop(fgets($fp));
69
			$data = decrypt_data($configtxt, $decrypt_password);
70
			if (!strstr($data, "<pfsense>")) {
71
				$data = "";
72
			}
73
			if ($data) {
74
				$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
75
				fwrite($fd, $data);
76
				fclose($fd);
77
				exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
78
				echo "\n" . gettext("Config.xml unlocked.") . "\n";
79
				fclose($fp);
80
				pfSense_fsync("{$g['conf_path']}/config.xml");
81
			} else {
82
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
83
			}
84
		}
85
	}
86
}
87

    
88
/****f* config/parse_config
89
 * NAME
90
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
91
 * INPUTS
92
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
93
 * RESULT
94
 *   $config      - array containing all configuration variables
95
 ******/
96
function parse_config($parse = false) {
97
	global $g, $config_parsed, $config_extra;
98

    
99
	$lockkey = lock('config');
100
	$config_parsed = false;
101

    
102
	if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
103
		$last_backup = discover_last_backup();
104
		if ($last_backup) {
105
			log_error(gettext("No config.xml found, attempting last known config restore."));
106
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
107
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
108
		} else {
109
			unlock($lockkey);
110
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
111
		}
112
	}
113

    
114
	if (platform_booting(true)) {
115
		echo ".";
116
	}
117

    
118
	// Check for encrypted config.xml
119
	encrypted_configxml();
120

    
121
	if (!$parse) {
122
		if (file_exists($g['tmp_path'] . '/config.cache')) {
123
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
124
			if (is_null($config)) {
125
				$parse = true;
126
			}
127
		} else {
128
			$parse = true;
129
		}
130
	}
131
	if ($parse == true) {
132
		if (!file_exists($g['conf_path'] . "/config.xml")) {
133
			if (platform_booting(true)) {
134
				echo ".";
135
			}
136
			log_error("No config.xml found, attempting last known config restore.");
137
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
138
			$last_backup = discover_last_backup();
139
			if ($last_backup) {
140
				restore_backup("/cf/conf/backup/{$last_backup}");
141
			} else {
142
				log_error(gettext("Could not restore config.xml."));
143
				unlock($lockkey);
144
				die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
145
			}
146
		}
147
		$config = parse_xml_config($g['conf_path'] . '/config.xml', array($g['xml_rootobj'], 'pfsense'));
148
		if ($config == -1) {
149
			$last_backup = discover_last_backup();
150
			if ($last_backup) {
151
				restore_backup("/cf/conf/backup/{$last_backup}");
152
			} else {
153
				log_error(gettext("Could not restore config.xml."));
154
				unlock($lockkey);
155
				die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
156
			}
157
		}
158
		generate_config_cache($config);
159
	}
160

    
161
	if (platform_booting(true)) {
162
		echo ".";
163
	}
164

    
165
	$config_parsed = true;
166
	unlock($lockkey);
167

    
168
	alias_make_table($config);
169

    
170
	return $config;
171
}
172

    
173
/****f* config/generate_config_cache
174
 * NAME
175
 *   generate_config_cache - Write serialized configuration to cache.
176
 * INPUTS
177
 *   $config	- array containing current firewall configuration
178
 * RESULT
179
 *   boolean	- true on completion
180
 ******/
181
function generate_config_cache($config) {
182
	global $g, $config_extra;
183

    
184
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
185
	fwrite($configcache, serialize($config));
186
	fclose($configcache);
187
	pfSense_fsync("{$g['tmp_path']}/config.cache");
188

    
189
	unset($configcache);
190
	/* Used for config.extra.xml */
191
	if (file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
192
		$configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
193
		fwrite($configcacheextra, serialize($config_extra));
194
		fclose($configcacheextra);
195
		pfSense_fsync("{$g['tmp_path']}/config.extra.cache");
196
		unset($configcacheextra);
197
	}
198
}
199

    
200
function discover_last_backup() {
201
	$backups = glob('/cf/conf/backup/*.xml');
202
	$last_backup = "";
203
	$last_mtime = 0;
204
	foreach ($backups as $backup) {
205
		if (filemtime($backup) > $last_mtime) {
206
			$last_mtime = filemtime($backup);
207
			$last_backup = $backup;
208
		}
209
	}
210

    
211
	return basename($last_backup);
212
}
213

    
214
function restore_backup($file) {
215
	global $g;
216

    
217
	if (file_exists($file)) {
218
		conf_mount_rw();
219
		unlink_if_exists("{$g['tmp_path']}/config.cache");
220
		copy("$file", "/cf/conf/config.xml");
221
		pfSense_fsync("/cf/conf/config.xml");
222
		pfSense_fsync($g['conf_path']);
223
		disable_security_checks();
224
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
225
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
226
		conf_mount_ro();
227
	}
228
}
229

    
230
/****f* config/parse_config_bootup
231
 * NAME
232
 *   parse_config_bootup - Bootup-specific configuration checks.
233
 * RESULT
234
 *   null
235
 ******/
236
function parse_config_bootup() {
237
	global $config, $g;
238

    
239
	if (platform_booting()) {
240
		echo ".";
241
	}
242

    
243
	$lockkey = lock('config');
244
	if (!file_exists("{$g['conf_path']}/config.xml")) {
245
		if (platform_booting()) {
246
			if (strstr($g['platform'], "cdrom")) {
247
				/* try copying the default config. to the floppy */
248
				echo gettext("Resetting factory defaults...") . "\n";
249
				reset_factory_defaults(true, false);
250
				if (!file_exists("{$g['conf_path']}/config.xml")) {
251
					echo gettext("No XML configuration file found - using factory defaults.\n" .
252
								 "Make sure that the configuration floppy disk with the conf/config.xml\n" .
253
								 "file is inserted. If it isn't, your configuration changes will be lost\n" .
254
								 "on reboot.\n");
255
				}
256
			} else {
257
				$last_backup = discover_last_backup();
258
				if ($last_backup) {
259
					log_error("No config.xml found, attempting last known config restore.");
260
					file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
261
					restore_backup("/cf/conf/backup/{$last_backup}");
262
				}
263
				if (!file_exists("{$g['conf_path']}/config.xml")) {
264
					echo sprintf(gettext("XML configuration file not found.  %s cannot continue booting."), $g['product_name']) . "\n";
265
					unlock($lockkey);
266
					mwexec("/sbin/halt");
267
					exit;
268
				}
269
				log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
270
				file_notice("config.xml", gettext("Last known config found and restored.  Please double check your configuration file for accuracy."), "pfSenseConfigurator", "");
271
			}
272
		} else {
273
			unlock($lockkey);
274
			log_error(gettext("Could not find a usable configuration file! Exiting...."));
275
			exit(0);
276
		}
277
	}
278

    
279
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
280
		$last_backup = discover_last_backup();
281
		if ($last_backup) {
282
			log_error(gettext("No config.xml found, attempting last known config restore."));
283
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
284
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
285
		} else {
286
			unlock($lockkey);
287
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
288
		}
289
	}
290
	unlock($lockkey);
291

    
292
	$config = parse_config(true);
293

    
294
	if ((float)$config['version'] > (float)$g['latest_config']) {
295
		echo <<<EOD
296

    
297

    
298
*******************************************************************************
299
* WARNING!                                                                    *
300
* The current configuration has been created with a newer version of {$g['product_name']}  *
301
* than this one! This can lead to serious misbehavior and even security       *
302
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
303
* revert to the default configuration immediately!                            *
304
*******************************************************************************
305

    
306

    
307
EOD;
308
		}
309

    
310
	/* make alias table (for faster lookups) */
311
	alias_make_table($config);
312
}
313

    
314
/****f* config/conf_mount_rw
315
 * NAME
316
 *   conf_mount_rw - Mount filesystems read/write.
317
 * RESULT
318
 *   null
319
 ******/
320
/* mount flash card read/write */
321
function conf_mount_rw() {
322
	global $g, $config;
323

    
324
	/* do not mount on cdrom platform */
325
	if ($g['platform'] == "cdrom" or $g['platform'] == $g['product_name']) {
326
		return;
327
	}
328

    
329
	if ((refcount_reference(1000) > 1) && is_writable("/")) {
330
		return;
331
	}
332

    
333
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
334
	if ($status <> 0) {
335
		if (platform_booting()) {
336
			echo gettext("/cf Filesystem is dirty.") . "\n";
337
		}
338
		$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
339
	}
340

    
341
	/*    if the platform is soekris or wrap or $product, lets mount the
342
	 *    compact flash cards root.
343
	*/
344
	$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
345
	/* we could not mount this correctly. */
346
	if ($status <> 0) {
347
		log_error(gettext("/ File system is dirty."));
348
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
349
	}
350

    
351
	mark_subsystem_dirty('mount');
352
}
353

    
354
/****f* config/conf_mount_ro
355
 * NAME
356
 *   conf_mount_ro - Mount filesystems readonly.
357
 * RESULT
358
 *   null
359
 ******/
360
function conf_mount_ro() {
361
	global $g, $config;
362

    
363
	/* Do not trust $g['platform'] since this can be clobbered during factory reset. */
364
	$platform = trim(file_get_contents("/etc/platform"));
365
	/* do not umount on cdrom or pfSense platforms */
366
	if ($platform == "cdrom" or $platform == $g['product_name']) {
367
		return;
368
	}
369

    
370
	if (refcount_unreference(1000) > 0) {
371
		return;
372
	}
373

    
374
	if (isset($config['system']['nanobsd_force_rw'])) {
375
		return;
376
	}
377

    
378
	if (platform_booting()) {
379
		return;
380
	}
381

    
382
	clear_subsystem_dirty('mount');
383
	/* sync data, then force a remount of /cf */
384
	pfSense_fsync($g['cf_path']);
385
	mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
386
	mwexec("/sbin/mount -u -r -f -o sync,noatime /");
387
}
388

    
389
/****f* config/convert_config
390
 * NAME
391
 *   convert_config - Attempt to update config.xml.
392
 * DESCRIPTION
393
 *   convert_config() reads the current global configuration
394
 *   and attempts to convert it to conform to the latest
395
 *   config.xml version. This allows major formatting changes
396
 *   to be made with a minimum of breakage.
397
 * RESULT
398
 *   null
399
 ******/
400
/* convert configuration, if necessary */
401
function convert_config() {
402
	global $config, $g;
403
	$now = date("H:i:s");
404
	log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
405
	//ini_set("max_execution_time", "900");
406

    
407
	/* special case upgrades */
408
	/* fix every minute crontab bogons entry */
409
	if (is_array($config['cron'])) {
410
		$cron_item_count = count($config['cron']['item']);
411
		for ($x = 0; $x < $cron_item_count; $x++) {
412
			if (stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
413
				if ($config['cron']['item'][$x]['hour'] == "*") {
414
					$config['cron']['item'][$x]['hour'] = "3";
415
					write_config(gettext("Updated bogon update frequency to 3am"));
416
					log_error(gettext("Updated bogon update frequency to 3am"));
417
				}
418
			}
419
		}
420
	}
421
	if ($config['version'] == $g['latest_config']) {
422
		return;		/* already at latest version */
423
	}
424

    
425
	// Save off config version
426
	$prev_version = $config['version'];
427

    
428
	include_once('auth.inc');
429
	include_once('upgrade_config.inc');
430
	if (file_exists("/etc/inc/upgrade_config_custom.inc")) {
431
		include_once("upgrade_config_custom.inc");
432
	}
433
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
434
	while ($config['version'] < $g['latest_config']) {
435
		$cur = $config['version'] * 10;
436
		$next = $cur + 1;
437
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
438
		if (function_exists($migration_function)) {
439
			$migration_function();
440
		}
441
		$migration_function = "{$migration_function}_custom";
442
		if (function_exists($migration_function)) {
443
			$migration_function();
444
		}
445
		$config['version'] = sprintf('%.1f', $next / 10);
446
		if (platform_booting()) {
447
			echo ".";
448
		}
449
	}
450

    
451
	$now = date("H:i:s");
452
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
453

    
454
	if ($prev_version != $config['version']) {
455
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
456
	}
457
}
458

    
459
/****f* config/safe_write_file
460
 * NAME
461
 *   safe_write_file - Write a file out atomically
462
 * DESCRIPTION
463
 *   safe_write_file() Writes a file out atomically by first writing to a
464
 *   temporary file of the same name but ending with the pid of the current
465
 *   process, them renaming the temporary file over the original.
466
 * INPUTS
467
 *   $filename  - string containing the filename of the file to write
468
 *   $content   - string containing the file content to write to file
469
 *   $force_binary      - boolean denoting whether we should force binary
470
 *   mode writing.
471
 * RESULT
472
 *   boolean - true if successful, false if not
473
 ******/
474
function safe_write_file($file, $content, $force_binary) {
475
	$tmp_file = $file . "." . getmypid();
476
	$write_mode = $force_binary ? "wb" : "w";
477

    
478
	$fd = fopen($tmp_file, $write_mode);
479
	if (!$fd) {
480
		// Unable to open temporary file for writing
481
		return false;
482
	}
483
	if (!fwrite($fd, $content)) {
484
		// Unable to write to temporary file
485
		fclose($fd);
486
		return false;
487
	}
488
	fflush($fd);
489
	fclose($fd);
490

    
491
	if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
492
		// Unable to move temporary file to original
493
		@unlink($tmp_file);
494
		return false;
495
	}
496

    
497
	// Sync file before returning
498
	return pfSense_fsync($file);
499
}
500

    
501
/****f* config/write_config
502
 * NAME
503
 *   write_config - Backup and write the firewall configuration.
504
 * DESCRIPTION
505
 *   write_config() handles backing up the current configuration,
506
 *   applying changes, and regenerating the configuration cache.
507
 * INPUTS
508
 *   $desc	- string containing the a description of configuration changes
509
 *   $backup	- boolean: do not back up current configuration if false.
510
 * RESULT
511
 *   null
512
 ******/
513
/* save the system configuration */
514
function write_config($desc="Unknown", $backup = true, $write_config_only = false) {
515
	global $config, $g;
516

    
517
	if (!empty($_SERVER['REMOTE_ADDR'])) {
518
		if (!session_id()) {
519
			@session_start();
520
		}
521
		if (!empty($_SESSION['Username']) && ($_SESSION['Username'] != "admin")) {
522
			$user = getUserEntry($_SESSION['Username']);
523
			if (is_array($user) && userHasPrivilege($user, "user-config-readonly")) {
524
				session_commit();
525
				return false;
526
			}
527
		}
528
	}
529

    
530
	if (!isset($argc)) {
531
		session_commit();
532
	}
533

    
534
	if ($backup) {
535
		backup_config();
536
	}
537

    
538
	$config['revision'] = make_config_revision_entry($desc);
539

    
540
	conf_mount_rw();
541
	$lockkey = lock('config', LOCK_EX);
542

    
543
	/* generate configuration XML */
544
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
545

    
546
	/* write new configuration */
547
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
548
		log_error(gettext("WARNING: Config contents could not be saved. Could not open file!"));
549
		unlock($lockkey);
550
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
551
		return -1;
552
	}
553

    
554
	cleanup_backupcache(true);
555

    
556
	/* re-read configuration */
557
	/* NOTE: We assume that the file can be parsed since we wrote it. */
558
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
559
	if ($config == -1) {
560
		copy("{$g['conf_path']}/config.xml", "{$g['conf_path']}/config.xml.bad");
561
		$last_backup = discover_last_backup();
562
		if ($last_backup) {
563
			restore_backup("/cf/conf/backup/{$last_backup}");
564
			$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
565
			if (platform_booting()) {
566
				echo "\n\n ************** WARNING **************";
567
				echo "\n\n Configuration could not be validated. A previous configuration was restored. \n";
568
				echo "\n The failed configuration file has been saved as {$g['conf_path']}/config.xml.bad \n\n";
569
			}
570
		} else {
571
			log_error(gettext("Could not restore config.xml."));
572
		}
573
	} else {
574
		generate_config_cache($config);
575
	}
576

    
577
	unlock($lockkey);
578

    
579
	if ($write_config_only) {
580
		/* tell kernel to sync fs data */
581
		conf_mount_ro();
582
		return $config;
583
	}
584

    
585
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
586

    
587
	/* tell kernel to sync fs data */
588
	conf_mount_ro();
589

    
590
	/* sync carp entries to other firewalls */
591
	carp_sync_client();
592

    
593
	if (is_dir("/usr/local/pkg/write_config")) {
594
		/* process packager manager custom rules */
595
		run_plugins("/usr/local/pkg/write_config/");
596
	}
597

    
598
	return $config;
599
}
600

    
601
/****f* config/reset_factory_defaults
602
 * NAME
603
 *   reset_factory_defaults - Reset the system to its default configuration.
604
 * RESULT
605
 *   integer	- indicates completion
606
 ******/
607
function reset_factory_defaults($lock = false, $reboot_required = true) {
608
	global $g;
609

    
610
	conf_mount_rw();
611
	if (!$lock) {
612
		$lockkey = lock('config', LOCK_EX);
613
	}
614

    
615
	/* create conf directory, if necessary */
616
	safe_mkdir("{$g['cf_conf_path']}");
617

    
618
	/* clear out /conf */
619
	$dh = opendir($g['conf_path']);
620
	while ($filename = readdir($dh)) {
621
		if (($filename != ".") && ($filename != "..") && (!is_dir($g['conf_path'] . "/" . $filename))) {
622
			unlink_if_exists($g['conf_path'] . "/" . $filename);
623
		}
624
	}
625
	closedir($dh);
626
	unlink_if_exists($g['tmp_path'] . "/config.cache");
627

    
628
	/* copy default configuration */
629
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
630

    
631
	disable_security_checks();
632

    
633
	/* call the wizard */
634
	if ($reboot_required) {
635
		// If we need a reboot first then touch a different trigger file.
636
		touch("/conf/trigger_initial_wizard_after_reboot");
637
	} else {
638
		touch("/conf/trigger_initial_wizard");
639
	}
640
	if (!$lock) {
641
		unlock($lockkey);
642
	}
643
	conf_mount_ro();
644
	setup_serial_port();
645
	return 0;
646
}
647

    
648
function config_restore($conffile) {
649
	global $config, $g;
650

    
651
	if (!file_exists($conffile)) {
652
		return 1;
653
	}
654

    
655
	backup_config();
656

    
657
	conf_mount_rw();
658

    
659
	$lockkey = lock('config', LOCK_EX);
660

    
661
	unlink_if_exists("{$g['tmp_path']}/config.cache");
662
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
663

    
664
	disable_security_checks();
665

    
666
	unlock($lockkey);
667

    
668
	$config = parse_config(true);
669

    
670
	conf_mount_ro();
671

    
672
	write_config(gettext("Reverted to") . " " . array_pop(explode("/", $conffile)) . ".", false);
673

    
674
	return 0;
675
}
676

    
677
function config_install($conffile) {
678
	global $config, $g;
679

    
680
	if (!file_exists($conffile)) {
681
		return 1;
682
	}
683

    
684
	if (!config_validate("{$conffile}")) {
685
		return 1;
686
	}
687

    
688
	if (platform_booting()) {
689
		echo gettext("Installing configuration...") . "\n";
690
	} else {
691
		log_error(gettext("Installing configuration ...."));
692
	}
693

    
694
	conf_mount_rw();
695
	$lockkey = lock('config', LOCK_EX);
696

    
697
	copy($conffile, "{$g['conf_path']}/config.xml");
698

    
699
	disable_security_checks();
700

    
701
	/* unlink cache file if it exists */
702
	if (file_exists("{$g['tmp_path']}/config.cache")) {
703
		unlink("{$g['tmp_path']}/config.cache");
704
	}
705

    
706
	unlock($lockkey);
707
	conf_mount_ro();
708

    
709
	return 0;
710
}
711

    
712
/*
713
 * Disable security checks for DNS rebind and HTTP referrer until next time
714
 * they pass (or reboot), to aid in preventing accidental lockout when
715
 * restoring settings like hostname, domain, IP addresses, and settings
716
 * related to the DNS rebind and HTTP referrer checks.
717
 * Intended for use when restoring a configuration or directly
718
 * modifying config.xml without an unconditional reboot.
719
 */
720
function disable_security_checks() {
721
	global $g;
722
	touch("{$g['tmp_path']}/disable_security_checks");
723
}
724

    
725
/* Restores security checks.  Should be called after all succeed. */
726
function restore_security_checks() {
727
	global $g;
728
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
729
}
730

    
731
/* Returns status of security check temporary disable. */
732
function security_checks_disabled() {
733
	global $g;
734
	return file_exists("{$g['tmp_path']}/disable_security_checks");
735
}
736

    
737
function config_validate($conffile) {
738

    
739
	global $g, $xmlerr;
740

    
741
	$xml_parser = xml_parser_create();
742

    
743
	if (!($fp = fopen($conffile, "r"))) {
744
		$xmlerr = gettext("XML error: unable to open file");
745
		return false;
746
	}
747

    
748
	while ($data = fread($fp, 4096)) {
749
		if (!xml_parse($xml_parser, $data, feof($fp))) {
750
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
751
						xml_error_string(xml_get_error_code($xml_parser)),
752
						xml_get_current_line_number($xml_parser));
753
			return false;
754
		}
755
	}
756
	xml_parser_free($xml_parser);
757

    
758
	fclose($fp);
759

    
760
	return true;
761
}
762

    
763
function cleanup_backupcache($lock = false) {
764
	global $g;
765
	$i = false;
766

    
767
	$revisions = get_config_backup_count();
768

    
769
	if (!$lock) {
770
		$lockkey = lock('config');
771
	}
772

    
773
	conf_mount_rw();
774

    
775
	$backups = get_backups();
776
	if ($backups) {
777
		$baktimes = $backups['versions'];
778
		unset($backups['versions']);
779
	} else {
780
		$backups = array();
781
		$baktimes = array();
782
	}
783
	$newbaks = array();
784
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
785
	$tocache = array();
786

    
787
	foreach ($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
788
		$backupsize = filesize($backup);
789
		if ($backupsize == 0) {
790
			unlink($backup);
791
			continue;
792
		}
793
		$backupexp = explode('-', $backup);
794
		$backupexp = explode('.', array_pop($backupexp));
795
		$tocheck = array_shift($backupexp);
796
		unset($backupexp);
797
		if (!in_array($tocheck, $baktimes)) {
798
			$i = true;
799
			if (platform_booting()) {
800
				echo ".";
801
			}
802
			$newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
803
			if ($newxml == "-1") {
804
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
805
				unlink($backup);
806
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
807
				continue;
808
			}
809
			if ($newxml['revision']['description'] == "") {
810
				$newxml['revision']['description'] = "Unknown";
811
			}
812
			if ($newxml['version'] == "") {
813
				$newxml['version'] = "?";
814
			}
815
			$tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version'], 'filesize' => $backupsize);
816
		}
817
	}
818
	foreach ($backups as $checkbak) {
819
		if (count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
820
			$newbaks[] = $checkbak;
821
		} else {
822
			$i = true;
823
			if (platform_booting()) print " " . $tocheck . "r";
824
		}
825
	}
826
	foreach ($newbaks as $todo) {
827
		$tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version'], 'filesize' => $todo['filesize']);
828
	}
829
	if (is_int($revisions) and (count($tocache) > $revisions)) {
830
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
831
		foreach ($toslice as $sliced) {
832
			$newcache[$sliced] = $tocache[$sliced];
833
		}
834
		foreach ($tocache as $version => $versioninfo) {
835
			if (!in_array($version, array_keys($newcache))) {
836
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
837
			}
838
		}
839
		$tocache = $newcache;
840
	}
841
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
842
	fwrite($bakout, serialize($tocache));
843
	fclose($bakout);
844
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
845
	conf_mount_ro();
846

    
847
	if (!$lock) {
848
		unlock($lockkey);
849
	}
850
}
851

    
852
function get_backups() {
853
	global $g;
854
	if (file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
855
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
856
		$bakvers = array_keys($confvers);
857
		$toreturn = array();
858
		sort($bakvers);
859
		// 	$bakvers = array_reverse($bakvers);
860
		foreach (array_reverse($bakvers) as $bakver) {
861
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
862
		}
863
	} else {
864
		return false;
865
	}
866
	$toreturn['versions'] = $bakvers;
867
	return $toreturn;
868
}
869

    
870
function backup_config() {
871
	global $config, $g;
872

    
873
	if ($g['platform'] == "cdrom") {
874
		return;
875
	}
876

    
877
	conf_mount_rw();
878

    
879
	/* Create backup directory if needed */
880
	safe_mkdir("{$g['cf_conf_path']}/backup");
881
	if ($config['revision']['time'] == "") {
882
		$baktime = 0;
883
	} else {
884
		$baktime = $config['revision']['time'];
885
	}
886

    
887
	if ($config['revision']['description'] == "") {
888
		$bakdesc = "Unknown";
889
	} else {
890
		$bakdesc = $config['revision']['description'];
891
	}
892

    
893
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
894
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
895
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
896

    
897
	if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
898
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
899
	} else {
900
		$backupcache = array();
901
	}
902
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
903
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
904
	fwrite($bakout, serialize($backupcache));
905
	fclose($bakout);
906
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
907

    
908
	conf_mount_ro();
909

    
910
	return true;
911
}
912

    
913
function set_device_perms() {
914
	$devices = array(
915
		'pf' => array(
916
			'user' => 'root',
917
			'group' => 'proxy',
918
			'mode' => 0660),
919
		);
920

    
921
	foreach ($devices as $name => $attr) {
922
		$path = "/dev/$name";
923
		if (file_exists($path)) {
924
			chown($path, $attr['user']);
925
			chgrp($path, $attr['group']);
926
			chmod($path, $attr['mode']);
927
		}
928
	}
929
}
930

    
931
function get_config_user() {
932
	if (empty($_SESSION["Username"])) {
933
		$username = getenv("USER");
934
		if (empty($conuser) || $conuser == "root") {
935
			$username = "(system)";
936
		}
937
	} else {
938
		$username = $_SESSION["Username"];
939
	}
940

    
941
	if (!empty($_SERVER['REMOTE_ADDR'])) {
942
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
943
	}
944

    
945
	return $username;
946
}
947

    
948
function make_config_revision_entry($desc = null, $override_user = null) {
949
	if (empty($override_user)) {
950
		$username = get_config_user();
951
	} else {
952
		$username = $override_user;
953
	}
954

    
955
	$revision = array();
956

    
957
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
958
		$revision['time'] = time();
959
	}
960

    
961
	/* Log the running script so it's not entirely unlogged what changed */
962
	if ($desc == "Unknown") {
963
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
964
	}
965
	if (!empty($desc)) {
966
		$revision['description'] = "{$username}: " . $desc;
967
	}
968
	$revision['username'] = $username;
969
	return $revision;
970
}
971

    
972
function get_config_backup_count() {
973
	global $config, $g;
974
	if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
975
		return intval($config['system']['backupcount']);
976
	} elseif ($g['platform'] == "nanobsd") {
977
		return 5;
978
	} else {
979
		return 30;
980
	}
981
}
982

    
983
function pfSense_clear_globals() {
984
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
985

    
986
	$error = error_get_last();
987

    
988
	if ($error !== NULL) {
989
		if ($error['type'] == E_ERROR) {
990
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
991
			print($errorstr);
992
			log_error($errorstr);
993
		} else if ($error['type'] != E_NOTICE) {
994
			$errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
995
			// XXX: comment out for now, should re-enable post-2.2
996
			//print($errorstr);
997
			//log_error($errorstr);
998
		}
999
	}
1000

    
1001
	if (isset($FilterIfList)) {
1002
		unset($FilterIfList);
1003
	}
1004

    
1005
	if (isset($GatewaysList)) {
1006
		unset($GatewaysList);
1007
	}
1008

    
1009
	/* Used for the hostname dns resolver */
1010
	if (isset($filterdns)) {
1011
		unset($filterdns);
1012
	}
1013

    
1014
	/* Used for aliases and interface macros */
1015
	if (isset($aliases)) {
1016
		unset($aliases);
1017
	}
1018
	if (isset($aliastable)) {
1019
		unset($aliastable);
1020
	}
1021

    
1022
	unset($config);
1023
}
1024

    
1025
register_shutdown_function('pfSense_clear_globals');
1026

    
1027
?>
(12-12/65)