Project

General

Profile

Download (28.4 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	/sbin/fsck
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
	// Check for encrypted config.xml
121
	encrypted_configxml();
122

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

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

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

    
170
	alias_make_table($config);
171

    
172
	return $config;
173
}
174

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

    
186
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
187
	fwrite($configcache, serialize($config));
188
	fclose($configcache);
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
		unset($configcacheextra);
196
	}
197
}
198

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

    
210
	return basename($last_backup);
211
}
212

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

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

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

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

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

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

    
289
	$config = parse_config(true);
290

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

    
294

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

    
303

    
304
EOD;
305
		}
306

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

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

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

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

    
330
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
331
	if ($status <> 0) {
332
		if (platform_booting()) {
333
			echo gettext("Disk is dirty.  Running fsck -y") . "\n";
334
		}
335
		mwexec("/sbin/fsck -y {$g['cf_path']}");
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.  kick off fsck */
344
	if ($status <> 0) {
345
		log_error(gettext("File system is dirty.  Launching FSCK for /"));
346
		mwexec("/sbin/fsck -y /");
347
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
348
	}
349

    
350
	mark_subsystem_dirty('mount');
351
}
352

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
499
	return true;
500
}
501

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

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

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

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

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

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

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

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

    
555
	cleanup_backupcache(true);
556

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

    
578
	unlock($lockkey);
579

    
580
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
581

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

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

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

    
593
	return $config;
594
}
595

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

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

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

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

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

    
626
	disable_security_checks();
627

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

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

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

    
645
	backup_config();
646

    
647
	conf_mount_rw();
648

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

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

    
654
	disable_security_checks();
655

    
656
	unlock($lockkey);
657

    
658
	$config = parse_config(true);
659

    
660
	conf_mount_ro();
661

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

    
664
	return 0;
665
}
666

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

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

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

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

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

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

    
689
	disable_security_checks();
690

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

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

    
699
	return 0;
700
}
701

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

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

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

    
727
function config_validate($conffile) {
728

    
729
	global $g, $xmlerr;
730

    
731
	$xml_parser = xml_parser_create();
732

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

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

    
748
	fclose($fp);
749

    
750
	return true;
751
}
752

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

    
757
	$revisions = get_config_backup_count();
758

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

    
763
	conf_mount_rw();
764

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

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

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

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

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

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

    
866
	conf_mount_rw();
867

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

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

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

    
895
	conf_mount_ro();
896

    
897
	return true;
898
}
899

    
900
function set_device_perms() {
901
	$devices = array(
902
		'pf'	=> array(	'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_NOTICE) {
976
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
977
			// XXX: comment out for now, should re-enable post-2.2
978
			//print($errorstr);
979
			//log_error($errorstr);
980
		}
981
	}
982

    
983
	if (isset($FilterIfList)) {
984
		unset($FilterIfList);
985
	}
986

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

    
991
	/* Used for the hostname dns resolver */
992
	if (isset($filterdns)) {
993
		unset($filterdns);
994
	}
995

    
996
	/* Used for aliases and interface macros */
997
	if (isset($aliases)) {
998
		unset($aliases);
999
	}
1000
	if (isset($aliastable)) {
1001
		unset($aliastable);
1002
	}
1003

    
1004
	unset($config);
1005
}
1006

    
1007
register_shutdown_function('pfSense_clear_globals');
1008

    
1009
?>
(13-13/68)