Project

General

Profile

Download (28.5 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
	pfSense_BUILDER_BINARIES:	/sbin/mount	/sbin/umount	/sbin/halt
43
	pfSense_MODULE:	config
44
*/
45

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

    
57
	if (!file_exists($g['conf_path'] . "/config.xml")) {
58
		return;
59
	}
60

    
61
	if (!platform_booting()) {
62
		return;
63
	}
64

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

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

    
102
	$lockkey = lock('config');
103
	$config_parsed = false;
104

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

    
117
	if (platform_booting(true)) {
118
		echo ".";
119
	}
120

    
121
	// Check for encrypted config.xml
122
	encrypted_configxml();
123

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

    
164
	if (platform_booting(true)) {
165
		echo ".";
166
	}
167

    
168
	$config_parsed = true;
169
	unlock($lockkey);
170

    
171
	alias_make_table($config);
172

    
173
	return $config;
174
}
175

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

    
187
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
188
	fwrite($configcache, serialize($config));
189
	fclose($configcache);
190
	unset($configcache);
191
	/* Used for config.extra.xml */
192
	if (file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
193
		$configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
194
		fwrite($configcacheextra, serialize($config_extra));
195
		fclose($configcacheextra);
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
		disable_security_checks();
222
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
223
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
224
		conf_mount_ro();
225
	}
226
}
227

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

    
237
	if (platform_booting()) {
238
		echo ".";
239
	}
240

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

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

    
290
	$config = parse_config(true);
291

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

    
295

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

    
304

    
305
EOD;
306
		}
307

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

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

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

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

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

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

    
349
	mark_subsystem_dirty('mount');
350
}
351

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

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

    
368
	if (refcount_unreference(1000) > 0) {
369
		return;
370
	}
371

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

    
376
	if (platform_booting()) {
377
		return;
378
	}
379

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

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

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

    
423
	// Save off config version
424
	$prev_version = $config['version'];
425

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

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

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

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

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

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

    
495
	// Sync file before returning
496
	pfSense_sync();
497

    
498
	return true;
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) {
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 save. 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
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
580

    
581
	/* tell kernel to sync fs data */
582
	conf_mount_ro();
583

    
584
	/* sync carp entries to other firewalls */
585
	carp_sync_client();
586

    
587
	if (is_dir("/usr/local/pkg/write_config")) {
588
		/* process packager manager custom rules */
589
		run_plugins("/usr/local/pkg/write_config/");
590
	}
591

    
592
	return $config;
593
}
594

    
595
/****f* config/reset_factory_defaults
596
 * NAME
597
 *   reset_factory_defaults - Reset the system to its default configuration.
598
 * RESULT
599
 *   integer	- indicates completion
600
 ******/
601
function reset_factory_defaults($lock = false) {
602
	global $g;
603

    
604
	conf_mount_rw();
605
	if (!$lock) {
606
		$lockkey = lock('config', LOCK_EX);
607
	}
608

    
609
	/* create conf directory, if necessary */
610
	safe_mkdir("{$g['cf_conf_path']}");
611

    
612
	/* clear out /conf */
613
	$dh = opendir($g['conf_path']);
614
	while ($filename = readdir($dh)) {
615
		if (($filename != ".") && ($filename != "..")) {
616
			unlink_if_exists($g['conf_path'] . "/" . $filename);
617
		}
618
	}
619
	closedir($dh);
620
	unlink_if_exists($g['tmp_path'] . "/config.cache");
621

    
622
	/* copy default configuration */
623
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
624

    
625
	disable_security_checks();
626

    
627
	/* call the wizard */
628
	touch("/conf/trigger_initial_wizard");
629
	if (!$lock) {
630
		unlock($lockkey);
631
	}
632
	conf_mount_ro();
633
	setup_serial_port();
634
	return 0;
635
}
636

    
637
function config_restore($conffile) {
638
	global $config, $g;
639

    
640
	if (!file_exists($conffile)) {
641
		return 1;
642
	}
643

    
644
	backup_config();
645

    
646
	conf_mount_rw();
647

    
648
	$lockkey = lock('config', LOCK_EX);
649

    
650
	unlink_if_exists("{$g['tmp_path']}/config.cache");
651
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
652

    
653
	disable_security_checks();
654

    
655
	unlock($lockkey);
656

    
657
	$config = parse_config(true);
658

    
659
	conf_mount_ro();
660

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

    
663
	return 0;
664
}
665

    
666
function config_install($conffile) {
667
	global $config, $g;
668

    
669
	if (!file_exists($conffile)) {
670
		return 1;
671
	}
672

    
673
	if (!config_validate("{$conffile}")) {
674
		return 1;
675
	}
676

    
677
	if (platform_booting()) {
678
		echo gettext("Installing configuration...") . "\n";
679
	} else {
680
		log_error(gettext("Installing configuration ...."));
681
	}
682

    
683
	conf_mount_rw();
684
	$lockkey = lock('config', LOCK_EX);
685

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

    
688
	disable_security_checks();
689

    
690
	/* unlink cache file if it exists */
691
	if (file_exists("{$g['tmp_path']}/config.cache")) {
692
		unlink("{$g['tmp_path']}/config.cache");
693
	}
694

    
695
	unlock($lockkey);
696
	conf_mount_ro();
697

    
698
	return 0;
699
}
700

    
701
/*
702
 * Disable security checks for DNS rebind and HTTP referrer until next time
703
 * they pass (or reboot), to aid in preventing accidental lockout when
704
 * restoring settings like hostname, domain, IP addresses, and settings
705
 * related to the DNS rebind and HTTP referrer checks.
706
 * Intended for use when restoring a configuration or directly
707
 * modifying config.xml without an unconditional reboot.
708
 */
709
function disable_security_checks() {
710
	global $g;
711
	touch("{$g['tmp_path']}/disable_security_checks");
712
}
713

    
714
/* Restores security checks.  Should be called after all succeed. */
715
function restore_security_checks() {
716
	global $g;
717
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
718
}
719

    
720
/* Returns status of security check temporary disable. */
721
function security_checks_disabled() {
722
	global $g;
723
	return file_exists("{$g['tmp_path']}/disable_security_checks");
724
}
725

    
726
function config_validate($conffile) {
727

    
728
	global $g, $xmlerr;
729

    
730
	$xml_parser = xml_parser_create();
731

    
732
	if (!($fp = fopen($conffile, "r"))) {
733
		$xmlerr = gettext("XML error: unable to open file");
734
		return false;
735
	}
736

    
737
	while ($data = fread($fp, 4096)) {
738
		if (!xml_parse($xml_parser, $data, feof($fp))) {
739
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
740
						xml_error_string(xml_get_error_code($xml_parser)),
741
						xml_get_current_line_number($xml_parser));
742
			return false;
743
		}
744
	}
745
	xml_parser_free($xml_parser);
746

    
747
	fclose($fp);
748

    
749
	return true;
750
}
751

    
752
function cleanup_backupcache($lock = false) {
753
	global $g;
754
	$i = false;
755

    
756
	$revisions = get_config_backup_count();
757

    
758
	if (!$lock) {
759
		$lockkey = lock('config');
760
	}
761

    
762
	conf_mount_rw();
763

    
764
	$backups = get_backups();
765
	if ($backups) {
766
		$baktimes = $backups['versions'];
767
		unset($backups['versions']);
768
	} else {
769
		$backups = array();
770
		$baktimes = array();
771
	}
772
	$newbaks = array();
773
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
774
	$tocache = array();
775

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

    
835
	if (!$lock) {
836
		unlock($lockkey);
837
	}
838
}
839

    
840
function get_backups() {
841
	global $g;
842
	if (file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
843
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
844
		$bakvers = array_keys($confvers);
845
		$toreturn = array();
846
		sort($bakvers);
847
		// 	$bakvers = array_reverse($bakvers);
848
		foreach (array_reverse($bakvers) as $bakver) {
849
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
850
		}
851
	} else {
852
		return false;
853
	}
854
	$toreturn['versions'] = $bakvers;
855
	return $toreturn;
856
}
857

    
858
function backup_config() {
859
	global $config, $g;
860

    
861
	if ($g['platform'] == "cdrom") {
862
		return;
863
	}
864

    
865
	conf_mount_rw();
866

    
867
	/* Create backup directory if needed */
868
	safe_mkdir("{$g['cf_conf_path']}/backup");
869

    
870
	if ($config['revision']['time'] == "") {
871
		$baktime = 0;
872
	} else {
873
		$baktime = $config['revision']['time'];
874
	}
875
	if ($config['revision']['description'] == "") {
876
		$bakdesc = "Unknown";
877
	} else {
878
		$bakdesc = $config['revision']['description'];
879
	}
880

    
881
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
882
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
883
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
884
	if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
885
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
886
	} else {
887
		$backupcache = array();
888
	}
889
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
890
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
891
	fwrite($bakout, serialize($backupcache));
892
	fclose($bakout);
893

    
894
	conf_mount_ro();
895

    
896
	return true;
897
}
898

    
899
function set_device_perms() {
900
	$devices = array(
901
		'pf' => array(
902
			'user' => 'root',
903
			'group' => 'proxy',
904
			'mode' => 0660),
905
		);
906

    
907
	foreach ($devices as $name => $attr) {
908
		$path = "/dev/$name";
909
		if (file_exists($path)) {
910
			chown($path, $attr['user']);
911
			chgrp($path, $attr['group']);
912
			chmod($path, $attr['mode']);
913
		}
914
	}
915
}
916

    
917
function get_config_user() {
918
	if (empty($_SESSION["Username"])) {
919
		$username = getenv("USER");
920
		if (empty($conuser) || $conuser == "root") {
921
			$username = "(system)";
922
		}
923
	} else {
924
		$username = $_SESSION["Username"];
925
	}
926

    
927
	if (!empty($_SERVER['REMOTE_ADDR'])) {
928
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
929
	}
930

    
931
	return $username;
932
}
933

    
934
function make_config_revision_entry($desc = null, $override_user = null) {
935
	if (empty($override_user)) {
936
		$username = get_config_user();
937
	} else {
938
		$username = $override_user;
939
	}
940

    
941
	$revision = array();
942

    
943
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
944
		$revision['time'] = time();
945
	}
946

    
947
	/* Log the running script so it's not entirely unlogged what changed */
948
	if ($desc == "Unknown") {
949
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
950
	}
951
	if (!empty($desc)) {
952
		$revision['description'] = "{$username}: " . $desc;
953
	}
954
	$revision['username'] = $username;
955
	return $revision;
956
}
957

    
958
function get_config_backup_count() {
959
	global $config, $g;
960
	if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
961
		return intval($config['system']['backupcount']);
962
	} elseif ($g['platform'] == "nanobsd") {
963
		return 5;
964
	} else {
965
		return 30;
966
	}
967
}
968

    
969
function pfSense_clear_globals() {
970
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
971

    
972
	$error = error_get_last();
973

    
974
	if ($error !== NULL) {
975
		if ($error['type'] == E_ERROR) {
976
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
977
			print($errorstr);
978
			log_error($errorstr);
979
		} else if ($error['type'] != E_NOTICE) {
980
			$errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
981
			// XXX: comment out for now, should re-enable post-2.2
982
			//print($errorstr);
983
			//log_error($errorstr);
984
		}
985
	}
986

    
987
	if (isset($FilterIfList)) {
988
		unset($FilterIfList);
989
	}
990

    
991
	if (isset($GatewaysList)) {
992
		unset($GatewaysList);
993
	}
994

    
995
	/* Used for the hostname dns resolver */
996
	if (isset($filterdns)) {
997
		unset($filterdns);
998
	}
999

    
1000
	/* Used for aliases and interface macros */
1001
	if (isset($aliases)) {
1002
		unset($aliases);
1003
	}
1004
	if (isset($aliastable)) {
1005
		unset($aliastable);
1006
	}
1007

    
1008
	unset($config);
1009
}
1010

    
1011
register_shutdown_function('pfSense_clear_globals');
1012

    
1013
?>
(12-12/68)