Project

General

Profile

Download (28.9 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
				pfSense_fsync("{$g['conf_path']}/config.xml");
85
			} else {
86
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
87
			}
88
		}
89
	}
90
}
91

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

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

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

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

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

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

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

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

    
172
	alias_make_table($config);
173

    
174
	return $config;
175
}
176

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

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

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

    
215
	return basename($last_backup);
216
}
217

    
218
function restore_backup($file) {
219
	global $g;
220

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

    
234
/****f* config/parse_config_bootup
235
 * NAME
236
 *   parse_config_bootup - Bootup-specific configuration checks.
237
 * RESULT
238
 *   null
239
 ******/
240
function parse_config_bootup() {
241
	global $config, $g;
242

    
243
	if (platform_booting()) {
244
		echo ".";
245
	}
246

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

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

    
296
	$config = parse_config(true);
297

    
298
	if ((float)$config['version'] > (float)$g['latest_config']) {
299
		echo <<<EOD
300

    
301

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

    
310

    
311
EOD;
312
		}
313

    
314
	/* make alias table (for faster lookups) */
315
	alias_make_table($config);
316
}
317

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

    
328
	/* do not mount on cdrom platform */
329
	if ($g['platform'] == "cdrom" or $g['platform'] == "pfSense") {
330
		return;
331
	}
332

    
333
	if ((refcount_reference(1000) > 1) && is_writable("/")) {
334
		return;
335
	}
336

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

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

    
355
	mark_subsystem_dirty('mount');
356
}
357

    
358
/****f* config/conf_mount_ro
359
 * NAME
360
 *   conf_mount_ro - Mount filesystems readonly.
361
 * RESULT
362
 *   null
363
 ******/
364
function conf_mount_ro() {
365
	global $g, $config;
366

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

    
374
	if (refcount_unreference(1000) > 0) {
375
		return;
376
	}
377

    
378
	if (isset($config['system']['nanobsd_force_rw'])) {
379
		return;
380
	}
381

    
382
	if (platform_booting()) {
383
		return;
384
	}
385

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

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

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

    
429
	// Save off config version
430
	$prev_version = $config['version'];
431

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

    
455
	$now = date("H:i:s");
456
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
457

    
458
	if ($prev_version != $config['version']) {
459
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
460
	}
461
}
462

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

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

    
495
	if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
496
		// Unable to move temporary file to original
497
		@unlink($tmp_file);
498
		return false;
499
	}
500

    
501
	// Sync file before returning
502
	return pfSense_fsync($file);
503
}
504

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

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

    
534
	if (!isset($argc)) {
535
		session_commit();
536
	}
537

    
538
	if ($backup) {
539
		backup_config();
540
	}
541

    
542
	$config['revision'] = make_config_revision_entry($desc);
543

    
544
	conf_mount_rw();
545
	$lockkey = lock('config', LOCK_EX);
546

    
547
	/* generate configuration XML */
548
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
549

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

    
558
	cleanup_backupcache(true);
559

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

    
581
	unlock($lockkey);
582

    
583
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
584

    
585
	/* tell kernel to sync fs data */
586
	conf_mount_ro();
587

    
588
	/* sync carp entries to other firewalls */
589
	carp_sync_client();
590

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

    
596
	return $config;
597
}
598

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

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

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

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

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

    
629
	disable_security_checks();
630

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

    
641
function config_restore($conffile) {
642
	global $config, $g;
643

    
644
	if (!file_exists($conffile)) {
645
		return 1;
646
	}
647

    
648
	backup_config();
649

    
650
	conf_mount_rw();
651

    
652
	$lockkey = lock('config', LOCK_EX);
653

    
654
	unlink_if_exists("{$g['tmp_path']}/config.cache");
655
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
656

    
657
	disable_security_checks();
658

    
659
	unlock($lockkey);
660

    
661
	$config = parse_config(true);
662

    
663
	conf_mount_ro();
664

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

    
667
	return 0;
668
}
669

    
670
function config_install($conffile) {
671
	global $config, $g;
672

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

    
677
	if (!config_validate("{$conffile}")) {
678
		return 1;
679
	}
680

    
681
	if (platform_booting()) {
682
		echo gettext("Installing configuration...") . "\n";
683
	} else {
684
		log_error(gettext("Installing configuration ...."));
685
	}
686

    
687
	conf_mount_rw();
688
	$lockkey = lock('config', LOCK_EX);
689

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

    
692
	disable_security_checks();
693

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

    
699
	unlock($lockkey);
700
	conf_mount_ro();
701

    
702
	return 0;
703
}
704

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

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

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

    
730
function config_validate($conffile) {
731

    
732
	global $g, $xmlerr;
733

    
734
	$xml_parser = xml_parser_create();
735

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

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

    
751
	fclose($fp);
752

    
753
	return true;
754
}
755

    
756
function cleanup_backupcache($lock = false) {
757
	global $g;
758
	$i = false;
759

    
760
	$revisions = get_config_backup_count();
761

    
762
	if (!$lock) {
763
		$lockkey = lock('config');
764
	}
765

    
766
	conf_mount_rw();
767

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

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

    
840
	if (!$lock) {
841
		unlock($lockkey);
842
	}
843
}
844

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

    
863
function backup_config() {
864
	global $config, $g;
865

    
866
	if ($g['platform'] == "cdrom") {
867
		return;
868
	}
869

    
870
	conf_mount_rw();
871

    
872
	/* Create backup directory if needed */
873
	safe_mkdir("{$g['cf_conf_path']}/backup");
874
	if ($config['revision']['time'] == "") {
875
		$baktime = 0;
876
	} else {
877
		$baktime = $config['revision']['time'];
878
	}
879

    
880
	if ($config['revision']['description'] == "") {
881
		$bakdesc = "Unknown";
882
	} else {
883
		$bakdesc = $config['revision']['description'];
884
	}
885

    
886
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
887
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
888
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
889

    
890
	if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
891
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
892
	} else {
893
		$backupcache = array();
894
	}
895
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
896
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
897
	fwrite($bakout, serialize($backupcache));
898
	fclose($bakout);
899
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
900

    
901
	conf_mount_ro();
902

    
903
	return true;
904
}
905

    
906
function set_device_perms() {
907
	$devices = array(
908
		'pf' => array(
909
			'user' => 'root',
910
			'group' => 'proxy',
911
			'mode' => 0660),
912
		);
913

    
914
	foreach ($devices as $name => $attr) {
915
		$path = "/dev/$name";
916
		if (file_exists($path)) {
917
			chown($path, $attr['user']);
918
			chgrp($path, $attr['group']);
919
			chmod($path, $attr['mode']);
920
		}
921
	}
922
}
923

    
924
function get_config_user() {
925
	if (empty($_SESSION["Username"])) {
926
		$username = getenv("USER");
927
		if (empty($conuser) || $conuser == "root") {
928
			$username = "(system)";
929
		}
930
	} else {
931
		$username = $_SESSION["Username"];
932
	}
933

    
934
	if (!empty($_SERVER['REMOTE_ADDR'])) {
935
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
936
	}
937

    
938
	return $username;
939
}
940

    
941
function make_config_revision_entry($desc = null, $override_user = null) {
942
	if (empty($override_user)) {
943
		$username = get_config_user();
944
	} else {
945
		$username = $override_user;
946
	}
947

    
948
	$revision = array();
949

    
950
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
951
		$revision['time'] = time();
952
	}
953

    
954
	/* Log the running script so it's not entirely unlogged what changed */
955
	if ($desc == "Unknown") {
956
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
957
	}
958
	if (!empty($desc)) {
959
		$revision['description'] = "{$username}: " . $desc;
960
	}
961
	$revision['username'] = $username;
962
	return $revision;
963
}
964

    
965
function get_config_backup_count() {
966
	global $config, $g;
967
	if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
968
		return intval($config['system']['backupcount']);
969
	} elseif ($g['platform'] == "nanobsd") {
970
		return 5;
971
	} else {
972
		return 30;
973
	}
974
}
975

    
976
function pfSense_clear_globals() {
977
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
978

    
979
	$error = error_get_last();
980

    
981
	if ($error !== NULL) {
982
		if ($error['type'] == E_ERROR) {
983
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
984
			print($errorstr);
985
			log_error($errorstr);
986
		} else if ($error['type'] != E_NOTICE) {
987
			$errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
988
			// XXX: comment out for now, should re-enable post-2.2
989
			//print($errorstr);
990
			//log_error($errorstr);
991
		}
992
	}
993

    
994
	if (isset($FilterIfList)) {
995
		unset($FilterIfList);
996
	}
997

    
998
	if (isset($GatewaysList)) {
999
		unset($GatewaysList);
1000
	}
1001

    
1002
	/* Used for the hostname dns resolver */
1003
	if (isset($filterdns)) {
1004
		unset($filterdns);
1005
	}
1006

    
1007
	/* Used for aliases and interface macros */
1008
	if (isset($aliases)) {
1009
		unset($aliases);
1010
	}
1011
	if (isset($aliastable)) {
1012
		unset($aliastable);
1013
	}
1014

    
1015
	unset($config);
1016
}
1017

    
1018
register_shutdown_function('pfSense_clear_globals');
1019

    
1020
?>
(12-12/68)