Project

General

Profile

Download (30.2 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	config.lib.inc
4

    
5
	Ported from config.inc by Erik Kristensen
6

    
7
	part of pfSense (https://www.pfsense.org)
8
	Copyright (c) 2004-2016 Electric Sheep Fencing, LLC. All rights reserved.
9

    
10
	originally part of m0n0wall (http://m0n0.ch/wall)
11
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
12
	All rights reserved.
13

    
14
	Redistribution and use in source and binary forms, with or without
15
	modification, are permitted provided that the following conditions are met:
16

    
17
	1. Redistributions of source code must retain the above copyright notice,
18
	   this list of conditions and the following disclaimer.
19

    
20
	2. Redistributions in binary form must reproduce the above copyright
21
	   notice, this list of conditions and the following disclaimer in
22
	   the documentation and/or other materials provided with the
23
	   distribution.
24

    
25
	3. All advertising materials mentioning features or use of this software
26
	   must display the following acknowledgment:
27
	   "This product includes software developed by the pfSense Project
28
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
29

    
30
	4. The names "pfSense" and "pfSense Project" must not be used to
31
	   endorse or promote products derived from this software without
32
	   prior written permission. For written permission, please contact
33
	   coreteam@pfsense.org.
34

    
35
	5. Products derived from this software may not be called "pfSense"
36
	   nor may "pfSense" appear in their names without prior written
37
	   permission of the Electric Sheep Fencing, LLC.
38

    
39
	6. Redistributions of any form whatsoever must retain the following
40
	   acknowledgment:
41

    
42
	"This product includes software developed by the pfSense Project
43
	for use in the pfSense software distribution (http://www.pfsense.org/).
44

    
45
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
46
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
49
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
54
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
56
	OF THE POSSIBILITY OF SUCH DAMAGE.
57
*/
58

    
59
/****f* config/encrypted_configxml
60
 * NAME
61
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
62
 * INPUTS
63
 *   None
64
 * RESULT
65
 *   $config 	- rewrites config.xml without encryption
66
 ******/
67
function encrypted_configxml() {
68
	global $g, $config;
69

    
70
	if (!file_exists($g['conf_path'] . "/config.xml")) {
71
		return;
72
	}
73

    
74
	if (!platform_booting()) {
75
		return;
76
	}
77

    
78
	$configtxt = file_get_contents($g['conf_path'] . "/config.xml");
79
	if (tagfile_deformat($configtxt, $configtxt, "config.xml")) {
80
		$fp = fopen('php://stdin', 'r');
81
		$data = "";
82
		echo "\n\n*** Encrypted config.xml detected ***\n";
83
		while ($data == "") {
84
			echo "\nEnter the password to decrypt config.xml: ";
85
			$decrypt_password = chop(fgets($fp));
86
			$data = decrypt_data($configtxt, $decrypt_password);
87
			if (!strstr($data, "<pfsense>")) {
88
				$data = "";
89
			}
90
			if ($data) {
91
				$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
92
				fwrite($fd, $data);
93
				fclose($fd);
94
				exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
95
				echo "\n" . gettext("Config.xml unlocked.") . "\n";
96
				fclose($fp);
97
				pfSense_fsync("{$g['conf_path']}/config.xml");
98
			} else {
99
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
100
			}
101
		}
102
	}
103
}
104

    
105
/****f* config/parse_config
106
 * NAME
107
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
108
 * INPUTS
109
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
110
 * RESULT
111
 *   $config      - array containing all configuration variables
112
 ******/
113
function parse_config($parse = false) {
114
	global $g, $config_parsed, $config_extra;
115

    
116
	$lockkey = lock('config');
117
	$config_parsed = false;
118

    
119
	if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
120
		$last_backup = discover_last_backup();
121
		if ($last_backup) {
122
			log_error(gettext("No config.xml found, attempting last known config restore."));
123
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
124
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
125
		} else {
126
			unlock($lockkey);
127
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
128
		}
129
	}
130

    
131
	if (platform_booting(true)) {
132
		echo ".";
133
	}
134

    
135
	// Check for encrypted config.xml
136
	encrypted_configxml();
137

    
138
	if (!$parse) {
139
		if (file_exists($g['tmp_path'] . '/config.cache')) {
140
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
141
			if (is_null($config)) {
142
				$parse = true;
143
			}
144
		} else {
145
			$parse = true;
146
		}
147
	}
148
	if ($parse == true) {
149
		if (!file_exists($g['conf_path'] . "/config.xml")) {
150
			if (platform_booting(true)) {
151
				echo ".";
152
			}
153
			log_error("No config.xml found, attempting last known config restore.");
154
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
155
			$last_backup = discover_last_backup();
156
			if ($last_backup) {
157
				restore_backup("/cf/conf/backup/{$last_backup}");
158
			} else {
159
				log_error(gettext("Could not restore config.xml."));
160
				unlock($lockkey);
161
				die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
162
			}
163
		}
164
		$config = parse_xml_config($g['conf_path'] . '/config.xml', array($g['xml_rootobj'], 'pfsense'));
165
		if ($config == -1) {
166
			$last_backup = discover_last_backup();
167
			if ($last_backup) {
168
				restore_backup("/cf/conf/backup/{$last_backup}");
169
			} else {
170
				log_error(gettext("Could not restore config.xml."));
171
				unlock($lockkey);
172
				die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
173
			}
174
		}
175
		generate_config_cache($config);
176
	}
177

    
178
	if (platform_booting(true)) {
179
		echo ".";
180
	}
181

    
182
	$config_parsed = true;
183
	unlock($lockkey);
184

    
185
	alias_make_table($config);
186

    
187
	return $config;
188
}
189

    
190
/****f* config/generate_config_cache
191
 * NAME
192
 *   generate_config_cache - Write serialized configuration to cache.
193
 * INPUTS
194
 *   $config	- array containing current firewall configuration
195
 * RESULT
196
 *   boolean	- true on completion
197
 ******/
198
function generate_config_cache($config) {
199
	global $g, $config_extra;
200

    
201
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
202
	fwrite($configcache, serialize($config));
203
	fclose($configcache);
204
	pfSense_fsync("{$g['tmp_path']}/config.cache");
205

    
206
	unset($configcache);
207
	/* Used for config.extra.xml */
208
	if (file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
209
		$configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
210
		fwrite($configcacheextra, serialize($config_extra));
211
		fclose($configcacheextra);
212
		pfSense_fsync("{$g['tmp_path']}/config.extra.cache");
213
		unset($configcacheextra);
214
	}
215
}
216

    
217
function discover_last_backup() {
218
	$backups = glob('/cf/conf/backup/*.xml');
219
	$last_backup = "";
220
	$last_mtime = 0;
221
	foreach ($backups as $backup) {
222
		if (filemtime($backup) > $last_mtime) {
223
			$last_mtime = filemtime($backup);
224
			$last_backup = $backup;
225
		}
226
	}
227

    
228
	return basename($last_backup);
229
}
230

    
231
function restore_backup($file) {
232
	global $g;
233

    
234
	if (file_exists($file)) {
235
		conf_mount_rw();
236
		unlink_if_exists("{$g['tmp_path']}/config.cache");
237
		copy("$file", "/cf/conf/config.xml");
238
		pfSense_fsync("/cf/conf/config.xml");
239
		pfSense_fsync($g['conf_path']);
240
		disable_security_checks();
241
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
242
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
243
		conf_mount_ro();
244
	}
245
}
246

    
247
/****f* config/parse_config_bootup
248
 * NAME
249
 *   parse_config_bootup - Bootup-specific configuration checks.
250
 * RESULT
251
 *   null
252
 ******/
253
function parse_config_bootup() {
254
	global $config, $g;
255

    
256
	if (platform_booting()) {
257
		echo ".";
258
	}
259

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

    
296
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
297
		$last_backup = discover_last_backup();
298
		if ($last_backup) {
299
			log_error(gettext("No config.xml found, attempting last known config restore."));
300
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
301
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
302
		} else {
303
			unlock($lockkey);
304
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
305
		}
306
	}
307
	unlock($lockkey);
308

    
309
	$config = parse_config(true);
310

    
311
	if ((float)$config['version'] > (float)$g['latest_config']) {
312
		echo <<<EOD
313

    
314

    
315
*******************************************************************************
316
* WARNING!                                                                    *
317
* The current configuration has been created with a newer version of {$g['product_name']}  *
318
* than this one! This can lead to serious misbehavior and even security       *
319
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
320
* revert to the default configuration immediately!                            *
321
*******************************************************************************
322

    
323

    
324
EOD;
325
		}
326

    
327
	/* make alias table (for faster lookups) */
328
	alias_make_table($config);
329
}
330

    
331
/****f* config/conf_mount_rw
332
 * NAME
333
 *   conf_mount_rw - Mount filesystems read/write.
334
 * RESULT
335
 *   null
336
 ******/
337
/* mount flash card read/write */
338
function conf_mount_rw() {
339
	global $g, $config;
340

    
341
	/* do not mount on cdrom platform */
342
	if ($g['platform'] == "cdrom" or $g['platform'] == $g['product_name']) {
343
		return;
344
	}
345

    
346
	if ((refcount_reference(1000) > 1) && is_writable("/")) {
347
		return;
348
	}
349

    
350
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
351
	if ($status <> 0) {
352
		if (platform_booting()) {
353
			echo gettext("/cf Filesystem is dirty.") . "\n";
354
		}
355
		$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
356
	}
357

    
358
	/*    if the platform is soekris or wrap or $product, lets mount the
359
	 *    compact flash cards root.
360
	*/
361
	$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
362
	/* we could not mount this correctly. */
363
	if ($status <> 0) {
364
		log_error(gettext("/ File system is dirty."));
365
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
366
	}
367

    
368
	mark_subsystem_dirty('mount');
369
}
370

    
371
/****f* config/conf_mount_ro
372
 * NAME
373
 *   conf_mount_ro - Mount filesystems readonly.
374
 * RESULT
375
 *   null
376
 ******/
377
function conf_mount_ro() {
378
	global $g, $config;
379

    
380
	/* Do not trust $g['platform'] since this can be clobbered during factory reset. */
381
	$platform = trim(file_get_contents("/etc/platform"));
382
	/* do not umount on cdrom or pfSense platforms */
383
	if ($platform == "cdrom" or $platform == $g['product_name']) {
384
		return;
385
	}
386

    
387
	if (refcount_unreference(1000) > 0) {
388
		return;
389
	}
390

    
391
	if (isset($config['system']['nanobsd_force_rw'])) {
392
		return;
393
	}
394

    
395
	if (platform_booting()) {
396
		return;
397
	}
398

    
399
	clear_subsystem_dirty('mount');
400
	/* sync data, then force a remount of /cf */
401
	pfSense_fsync($g['cf_path']);
402
	mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
403
	mwexec("/sbin/mount -u -r -f -o sync,noatime /");
404
}
405

    
406
/****f* config/convert_config
407
 * NAME
408
 *   convert_config - Attempt to update config.xml.
409
 * DESCRIPTION
410
 *   convert_config() reads the current global configuration
411
 *   and attempts to convert it to conform to the latest
412
 *   config.xml version. This allows major formatting changes
413
 *   to be made with a minimum of breakage.
414
 * RESULT
415
 *   null
416
 ******/
417
/* convert configuration, if necessary */
418
function convert_config() {
419
	global $config, $g;
420
	$now = date("H:i:s");
421
	log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
422
	//ini_set("max_execution_time", "900");
423

    
424
	/* special case upgrades */
425
	/* fix every minute crontab bogons entry */
426
	if (is_array($config['cron'])) {
427
		$cron_item_count = count($config['cron']['item']);
428
		for ($x = 0; $x < $cron_item_count; $x++) {
429
			if (stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
430
				if ($config['cron']['item'][$x]['hour'] == "*") {
431
					$config['cron']['item'][$x]['hour'] = "3";
432
					write_config(gettext("Updated bogon update frequency to 3am"));
433
					log_error(gettext("Updated bogon update frequency to 3am"));
434
				}
435
			}
436
		}
437
	}
438
	if ($config['version'] == $g['latest_config']) {
439
		return;		/* already at latest version */
440
	}
441

    
442
	// Save off config version
443
	$prev_version = $config['version'];
444

    
445
	include_once('auth.inc');
446
	include_once('upgrade_config.inc');
447
	if (file_exists("/etc/inc/upgrade_config_custom.inc")) {
448
		include_once("upgrade_config_custom.inc");
449
	}
450
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
451
	while ($config['version'] < $g['latest_config']) {
452
		$cur = $config['version'] * 10;
453
		$next = $cur + 1;
454
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
455
		if (function_exists($migration_function)) {
456
			$migration_function();
457
		}
458
		$migration_function = "{$migration_function}_custom";
459
		if (function_exists($migration_function)) {
460
			$migration_function();
461
		}
462
		$config['version'] = sprintf('%.1f', $next / 10);
463
		if (platform_booting()) {
464
			echo ".";
465
		}
466
	}
467

    
468
	$now = date("H:i:s");
469
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
470

    
471
	if ($prev_version != $config['version']) {
472
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
473
	}
474
}
475

    
476
/****f* config/safe_write_file
477
 * NAME
478
 *   safe_write_file - Write a file out atomically
479
 * DESCRIPTION
480
 *   safe_write_file() Writes a file out atomically by first writing to a
481
 *   temporary file of the same name but ending with the pid of the current
482
 *   process, them renaming the temporary file over the original.
483
 * INPUTS
484
 *   $filename  - string containing the filename of the file to write
485
 *   $content   - string containing the file content to write to file
486
 *   $force_binary      - boolean denoting whether we should force binary
487
 *   mode writing.
488
 * RESULT
489
 *   boolean - true if successful, false if not
490
 ******/
491
function safe_write_file($file, $content, $force_binary) {
492
	$tmp_file = $file . "." . getmypid();
493
	$write_mode = $force_binary ? "wb" : "w";
494

    
495
	$fd = fopen($tmp_file, $write_mode);
496
	if (!$fd) {
497
		// Unable to open temporary file for writing
498
		return false;
499
	}
500
	if (!fwrite($fd, $content)) {
501
		// Unable to write to temporary file
502
		fclose($fd);
503
		return false;
504
	}
505
	fflush($fd);
506
	fclose($fd);
507

    
508
	if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
509
		// Unable to move temporary file to original
510
		@unlink($tmp_file);
511
		return false;
512
	}
513

    
514
	// Sync file before returning
515
	return pfSense_fsync($file);
516
}
517

    
518
/****f* config/write_config
519
 * NAME
520
 *   write_config - Backup and write the firewall configuration.
521
 * DESCRIPTION
522
 *   write_config() handles backing up the current configuration,
523
 *   applying changes, and regenerating the configuration cache.
524
 * INPUTS
525
 *   $desc	- string containing the a description of configuration changes
526
 *   $backup	- boolean: do not back up current configuration if false.
527
 *   $write_config_only	- boolean: do not sync or reload anything; just save the configuration if true.
528
 * RESULT
529
 *   null
530
 ******/
531
/* save the system configuration */
532
function write_config($desc="Unknown", $backup = true, $write_config_only = false) {
533
	global $config, $g;
534

    
535
	if (!empty($_SERVER['REMOTE_ADDR'])) {
536
		if (!session_id()) {
537
			@session_start();
538
		}
539
		if (!empty($_SESSION['Username']) && ($_SESSION['Username'] != "admin")) {
540
			$user = getUserEntry($_SESSION['Username']);
541
			if (is_array($user) && userHasPrivilege($user, "user-config-readonly")) {
542
				session_commit();
543
				return false;
544
			}
545
		}
546
	}
547

    
548
	if (!isset($argc)) {
549
		session_commit();
550
	}
551

    
552
	if ($backup) {
553
		backup_config();
554
	}
555

    
556
	$config['revision'] = make_config_revision_entry($desc);
557

    
558
	conf_mount_rw();
559
	$lockkey = lock('config', LOCK_EX);
560

    
561
	/* generate configuration XML */
562
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
563

    
564
	/* write new configuration */
565
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
566
		log_error(gettext("WARNING: Config contents could not be saved. Could not open file!"));
567
		unlock($lockkey);
568
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
569
		return -1;
570
	}
571

    
572
	cleanup_backupcache(true);
573

    
574
	/* re-read configuration */
575
	/* NOTE: We assume that the file can be parsed since we wrote it. */
576
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
577
	if ($config == -1) {
578
		copy("{$g['conf_path']}/config.xml", "{$g['conf_path']}/config.xml.bad");
579
		$last_backup = discover_last_backup();
580
		if ($last_backup) {
581
			restore_backup("/cf/conf/backup/{$last_backup}");
582
			$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
583
			if (platform_booting()) {
584
				echo "\n\n ************** WARNING **************";
585
				echo "\n\n Configuration could not be validated. A previous configuration was restored. \n";
586
				echo "\n The failed configuration file has been saved as {$g['conf_path']}/config.xml.bad \n\n";
587
			}
588
		} else {
589
			log_error(gettext("Could not restore config.xml."));
590
		}
591
	} else {
592
		generate_config_cache($config);
593
	}
594

    
595
	unlock($lockkey);
596

    
597
	if ($write_config_only) {
598
		/* tell kernel to sync fs data */
599
		conf_mount_ro();
600
		return $config;
601
	}
602

    
603
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
604

    
605
	/* tell kernel to sync fs data */
606
	conf_mount_ro();
607

    
608
	/* sync carp entries to other firewalls */
609
	carp_sync_client();
610

    
611
	if (is_dir("/usr/local/pkg/write_config")) {
612
		/* process packager manager custom rules */
613
		run_plugins("/usr/local/pkg/write_config/");
614
	}
615

    
616
	return $config;
617
}
618

    
619
/****f* config/reset_factory_defaults
620
 * NAME
621
 *   reset_factory_defaults - Reset the system to its default configuration.
622
 * RESULT
623
 *   integer	- indicates completion
624
 ******/
625
function reset_factory_defaults($lock = false, $reboot_required = true) {
626
	global $g;
627

    
628
	conf_mount_rw();
629

    
630
	/* Remove all additional packages */
631
	mwexec("/bin/sh /usr/local/sbin/{$g['product_name']}-upgrade " .
632
	    "-r ALL_PACKAGES");
633

    
634
	if (!$lock) {
635
		$lockkey = lock('config', LOCK_EX);
636
	}
637

    
638
	/* create conf directory, if necessary */
639
	safe_mkdir($g['cf_conf_path']);
640

    
641
	/* clear out /conf */
642
	$dh = opendir($g['conf_path']);
643
	while ($filename = readdir($dh)) {
644
		if (($filename != ".") && ($filename != "..") &&
645
		    (!is_dir($g['conf_path'] . "/" . $filename))) {
646
			unlink_if_exists($g['conf_path'] . "/" . $filename);
647
		}
648
	}
649
	closedir($dh);
650
	unlink_if_exists($g['tmp_path'] . "/config.cache");
651

    
652
	/* copy default configuration */
653
	copy("{$g['conf_default_path']}/config.xml",
654
	    "{$g['cf_conf_path']}/config.xml");
655

    
656
	disable_security_checks();
657

    
658
	/* call the wizard */
659
	if ($reboot_required) {
660
		// If we need a reboot first then touch a different trigger file.
661
		touch("/conf/trigger_initial_wizard_after_reboot");
662
	} else {
663
		touch("/conf/trigger_initial_wizard");
664
	}
665
	if (!$lock) {
666
		unlock($lockkey);
667
	}
668
	conf_mount_ro();
669
	setup_serial_port();
670
	return 0;
671
}
672

    
673
function config_restore($conffile) {
674
	global $config, $g;
675

    
676
	if (!file_exists($conffile)) {
677
		return 1;
678
	}
679

    
680
	backup_config();
681

    
682
	conf_mount_rw();
683

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

    
686
	unlink_if_exists("{$g['tmp_path']}/config.cache");
687
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
688

    
689
	disable_security_checks();
690

    
691
	unlock($lockkey);
692

    
693
	$config = parse_config(true);
694

    
695
	conf_mount_ro();
696

    
697
	write_config(sprintf(gettext("Reverted to %s."), array_pop(explode("/", $conffile))), false);
698

    
699
	return 0;
700
}
701

    
702
function config_install($conffile) {
703
	global $config, $g;
704

    
705
	if (!file_exists($conffile)) {
706
		return 1;
707
	}
708

    
709
	if (!config_validate("{$conffile}")) {
710
		return 1;
711
	}
712

    
713
	if (platform_booting()) {
714
		echo gettext("Installing configuration...") . "\n";
715
	} else {
716
		log_error(gettext("Installing configuration ...."));
717
	}
718

    
719
	conf_mount_rw();
720
	$lockkey = lock('config', LOCK_EX);
721

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

    
724
	disable_security_checks();
725

    
726
	/* unlink cache file if it exists */
727
	if (file_exists("{$g['tmp_path']}/config.cache")) {
728
		unlink("{$g['tmp_path']}/config.cache");
729
	}
730

    
731
	unlock($lockkey);
732
	conf_mount_ro();
733

    
734
	return 0;
735
}
736

    
737
/*
738
 * Disable security checks for DNS rebind and HTTP referrer until next time
739
 * they pass (or reboot), to aid in preventing accidental lockout when
740
 * restoring settings like hostname, domain, IP addresses, and settings
741
 * related to the DNS rebind and HTTP referrer checks.
742
 * Intended for use when restoring a configuration or directly
743
 * modifying config.xml without an unconditional reboot.
744
 */
745
function disable_security_checks() {
746
	global $g;
747
	touch("{$g['tmp_path']}/disable_security_checks");
748
}
749

    
750
/* Restores security checks.  Should be called after all succeed. */
751
function restore_security_checks() {
752
	global $g;
753
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
754
}
755

    
756
/* Returns status of security check temporary disable. */
757
function security_checks_disabled() {
758
	global $g;
759
	return file_exists("{$g['tmp_path']}/disable_security_checks");
760
}
761

    
762
function config_validate($conffile) {
763

    
764
	global $g, $xmlerr;
765

    
766
	$xml_parser = xml_parser_create();
767

    
768
	if (!($fp = fopen($conffile, "r"))) {
769
		$xmlerr = gettext("XML error: unable to open file");
770
		return false;
771
	}
772

    
773
	while ($data = fread($fp, 4096)) {
774
		if (!xml_parse($xml_parser, $data, feof($fp))) {
775
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
776
						xml_error_string(xml_get_error_code($xml_parser)),
777
						xml_get_current_line_number($xml_parser));
778
			return false;
779
		}
780
	}
781
	xml_parser_free($xml_parser);
782

    
783
	fclose($fp);
784

    
785
	return true;
786
}
787

    
788
function cleanup_backupcache($lock = false) {
789
	global $g;
790
	$i = false;
791

    
792
	$revisions = get_config_backup_count();
793

    
794
	if (!$lock) {
795
		$lockkey = lock('config');
796
	}
797

    
798
	conf_mount_rw();
799

    
800
	$backups = get_backups();
801
	if ($backups) {
802
		$baktimes = $backups['versions'];
803
		unset($backups['versions']);
804
	} else {
805
		$backups = array();
806
		$baktimes = array();
807
	}
808
	$newbaks = array();
809
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
810
	$tocache = array();
811

    
812
	foreach ($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
813
		$backupsize = filesize($backup);
814
		if ($backupsize == 0) {
815
			unlink($backup);
816
			continue;
817
		}
818
		$backupexp = explode('-', $backup);
819
		$backupexp = explode('.', array_pop($backupexp));
820
		$tocheck = array_shift($backupexp);
821
		unset($backupexp);
822
		if (!in_array($tocheck, $baktimes)) {
823
			$i = true;
824
			if (platform_booting()) {
825
				echo ".";
826
			}
827
			$newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
828
			if ($newxml == "-1") {
829
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
830
				unlink($backup);
831
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
832
				continue;
833
			}
834
			if ($newxml['revision']['description'] == "") {
835
				$newxml['revision']['description'] = "Unknown";
836
			}
837
			if ($newxml['version'] == "") {
838
				$newxml['version'] = "?";
839
			}
840
			$tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version'], 'filesize' => $backupsize);
841
		}
842
	}
843
	foreach ($backups as $checkbak) {
844
		if (count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
845
			$newbaks[] = $checkbak;
846
		} else {
847
			$i = true;
848
			if (platform_booting()) print " " . $tocheck . "r";
849
		}
850
	}
851
	foreach ($newbaks as $todo) {
852
		$tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version'], 'filesize' => $todo['filesize']);
853
	}
854
	if (is_int($revisions) and (count($tocache) > $revisions)) {
855
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
856
		foreach ($toslice as $sliced) {
857
			$newcache[$sliced] = $tocache[$sliced];
858
		}
859
		foreach ($tocache as $version => $versioninfo) {
860
			if (!in_array($version, array_keys($newcache))) {
861
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
862
			}
863
		}
864
		$tocache = $newcache;
865
	}
866
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
867
	fwrite($bakout, serialize($tocache));
868
	fclose($bakout);
869
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
870
	conf_mount_ro();
871

    
872
	if (!$lock) {
873
		unlock($lockkey);
874
	}
875
}
876

    
877
function get_backups() {
878
	global $g;
879
	if (file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
880
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
881
		$bakvers = array_keys($confvers);
882
		$toreturn = array();
883
		sort($bakvers);
884
		// 	$bakvers = array_reverse($bakvers);
885
		foreach (array_reverse($bakvers) as $bakver) {
886
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
887
		}
888
	} else {
889
		return false;
890
	}
891
	$toreturn['versions'] = $bakvers;
892
	return $toreturn;
893
}
894

    
895
function backup_config() {
896
	global $config, $g;
897

    
898
	if ($g['platform'] == "cdrom") {
899
		return;
900
	}
901

    
902
	conf_mount_rw();
903

    
904
	/* Create backup directory if needed */
905
	safe_mkdir("{$g['cf_conf_path']}/backup");
906
	if ($config['revision']['time'] == "") {
907
		$baktime = 0;
908
	} else {
909
		$baktime = $config['revision']['time'];
910
	}
911

    
912
	if ($config['revision']['description'] == "") {
913
		$bakdesc = "Unknown";
914
	} else {
915
		$bakdesc = $config['revision']['description'];
916
	}
917

    
918
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
919
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
920
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
921

    
922
	if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
923
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
924
	} else {
925
		$backupcache = array();
926
	}
927
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
928
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
929
	fwrite($bakout, serialize($backupcache));
930
	fclose($bakout);
931
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
932

    
933
	conf_mount_ro();
934

    
935
	return true;
936
}
937

    
938
function set_device_perms() {
939
	$devices = array(
940
		'pf' => array(
941
			'user' => 'root',
942
			'group' => 'proxy',
943
			'mode' => 0660),
944
		);
945

    
946
	foreach ($devices as $name => $attr) {
947
		$path = "/dev/$name";
948
		if (file_exists($path)) {
949
			chown($path, $attr['user']);
950
			chgrp($path, $attr['group']);
951
			chmod($path, $attr['mode']);
952
		}
953
	}
954
}
955

    
956
function get_config_user() {
957
	if (empty($_SESSION["Username"])) {
958
		$username = getenv("USER");
959
		if (empty($conuser) || $conuser == "root") {
960
			$username = "(system)";
961
		}
962
	} else {
963
		$username = $_SESSION["Username"];
964
	}
965

    
966
	if (!empty($_SERVER['REMOTE_ADDR'])) {
967
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
968
	}
969

    
970
	return $username;
971
}
972

    
973
function make_config_revision_entry($desc = null, $override_user = null) {
974
	if (empty($override_user)) {
975
		$username = get_config_user();
976
	} else {
977
		$username = $override_user;
978
	}
979

    
980
	$revision = array();
981

    
982
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
983
		$revision['time'] = time();
984
	}
985

    
986
	/* Log the running script so it's not entirely unlogged what changed */
987
	if ($desc == "Unknown") {
988
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
989
	}
990
	if (!empty($desc)) {
991
		$revision['description'] = "{$username}: " . $desc;
992
	}
993
	$revision['username'] = $username;
994
	return $revision;
995
}
996

    
997
function get_config_backup_count() {
998
	global $config, $g;
999
	if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
1000
		return intval($config['system']['backupcount']);
1001
	} elseif ($g['platform'] == "nanobsd") {
1002
		return 5;
1003
	} else {
1004
		return 30;
1005
	}
1006
}
1007

    
1008
function pfSense_clear_globals() {
1009
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
1010

    
1011
	$error = error_get_last();
1012

    
1013
	if ($error !== NULL) {
1014
		if ($error['type'] == E_ERROR) {
1015
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
1016
			print($errorstr);
1017
			log_error($errorstr);
1018
		} else if ($error['type'] != E_NOTICE) {
1019
			$errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
1020
			// XXX: comment out for now, should re-enable post-2.2
1021
			//print($errorstr);
1022
			//log_error($errorstr);
1023
		}
1024
	}
1025

    
1026
	if (isset($FilterIfList)) {
1027
		unset($FilterIfList);
1028
	}
1029

    
1030
	if (isset($GatewaysList)) {
1031
		unset($GatewaysList);
1032
	}
1033

    
1034
	/* Used for the hostname dns resolver */
1035
	if (isset($filterdns)) {
1036
		unset($filterdns);
1037
	}
1038

    
1039
	/* Used for aliases and interface macros */
1040
	if (isset($aliases)) {
1041
		unset($aliases);
1042
	}
1043
	if (isset($aliastable)) {
1044
		unset($aliastable);
1045
	}
1046

    
1047
	unset($config);
1048
}
1049

    
1050
register_shutdown_function('pfSense_clear_globals');
1051

    
1052
?>
(12-12/65)