Project

General

Profile

Download (30.1 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
 * RESULT
528
 *   null
529
 ******/
530
/* save the system configuration */
531
function write_config($desc="Unknown", $backup = true, $write_config_only = false) {
532
	global $config, $g;
533

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

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

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

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

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

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

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

    
571
	cleanup_backupcache(true);
572

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

    
594
	unlock($lockkey);
595

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

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

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

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

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

    
615
	return $config;
616
}
617

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

    
627
	/* Remove all additional packages */
628

    
629
	mwexec("/bin/sh /usr/local/sbin/{$g['product_name']}-upgrade -r ALL_PACKAGES");
630

    
631
	conf_mount_rw();
632
	if (!$lock) {
633
		$lockkey = lock('config', LOCK_EX);
634
	}
635

    
636
	/* create conf directory, if necessary */
637
	safe_mkdir("{$g['cf_conf_path']}");
638

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

    
649
	/* copy default configuration */
650
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
651

    
652
	disable_security_checks();
653

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

    
669
function config_restore($conffile) {
670
	global $config, $g;
671

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

    
676
	backup_config();
677

    
678
	conf_mount_rw();
679

    
680
	$lockkey = lock('config', LOCK_EX);
681

    
682
	unlink_if_exists("{$g['tmp_path']}/config.cache");
683
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
684

    
685
	disable_security_checks();
686

    
687
	unlock($lockkey);
688

    
689
	$config = parse_config(true);
690

    
691
	conf_mount_ro();
692

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

    
695
	return 0;
696
}
697

    
698
function config_install($conffile) {
699
	global $config, $g;
700

    
701
	if (!file_exists($conffile)) {
702
		return 1;
703
	}
704

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

    
709
	if (platform_booting()) {
710
		echo gettext("Installing configuration...") . "\n";
711
	} else {
712
		log_error(gettext("Installing configuration ...."));
713
	}
714

    
715
	conf_mount_rw();
716
	$lockkey = lock('config', LOCK_EX);
717

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

    
720
	disable_security_checks();
721

    
722
	/* unlink cache file if it exists */
723
	if (file_exists("{$g['tmp_path']}/config.cache")) {
724
		unlink("{$g['tmp_path']}/config.cache");
725
	}
726

    
727
	unlock($lockkey);
728
	conf_mount_ro();
729

    
730
	return 0;
731
}
732

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

    
746
/* Restores security checks.  Should be called after all succeed. */
747
function restore_security_checks() {
748
	global $g;
749
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
750
}
751

    
752
/* Returns status of security check temporary disable. */
753
function security_checks_disabled() {
754
	global $g;
755
	return file_exists("{$g['tmp_path']}/disable_security_checks");
756
}
757

    
758
function config_validate($conffile) {
759

    
760
	global $g, $xmlerr;
761

    
762
	$xml_parser = xml_parser_create();
763

    
764
	if (!($fp = fopen($conffile, "r"))) {
765
		$xmlerr = gettext("XML error: unable to open file");
766
		return false;
767
	}
768

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

    
779
	fclose($fp);
780

    
781
	return true;
782
}
783

    
784
function cleanup_backupcache($lock = false) {
785
	global $g;
786
	$i = false;
787

    
788
	$revisions = get_config_backup_count();
789

    
790
	if (!$lock) {
791
		$lockkey = lock('config');
792
	}
793

    
794
	conf_mount_rw();
795

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

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

    
868
	if (!$lock) {
869
		unlock($lockkey);
870
	}
871
}
872

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

    
891
function backup_config() {
892
	global $config, $g;
893

    
894
	if ($g['platform'] == "cdrom") {
895
		return;
896
	}
897

    
898
	conf_mount_rw();
899

    
900
	/* Create backup directory if needed */
901
	safe_mkdir("{$g['cf_conf_path']}/backup");
902
	if ($config['revision']['time'] == "") {
903
		$baktime = 0;
904
	} else {
905
		$baktime = $config['revision']['time'];
906
	}
907

    
908
	if ($config['revision']['description'] == "") {
909
		$bakdesc = "Unknown";
910
	} else {
911
		$bakdesc = $config['revision']['description'];
912
	}
913

    
914
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
915
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
916
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
917

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

    
929
	conf_mount_ro();
930

    
931
	return true;
932
}
933

    
934
function set_device_perms() {
935
	$devices = array(
936
		'pf' => array(
937
			'user' => 'root',
938
			'group' => 'proxy',
939
			'mode' => 0660),
940
		);
941

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

    
952
function get_config_user() {
953
	if (empty($_SESSION["Username"])) {
954
		$username = getenv("USER");
955
		if (empty($conuser) || $conuser == "root") {
956
			$username = "(system)";
957
		}
958
	} else {
959
		$username = $_SESSION["Username"];
960
	}
961

    
962
	if (!empty($_SERVER['REMOTE_ADDR'])) {
963
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
964
	}
965

    
966
	return $username;
967
}
968

    
969
function make_config_revision_entry($desc = null, $override_user = null) {
970
	if (empty($override_user)) {
971
		$username = get_config_user();
972
	} else {
973
		$username = $override_user;
974
	}
975

    
976
	$revision = array();
977

    
978
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
979
		$revision['time'] = time();
980
	}
981

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

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

    
1004
function pfSense_clear_globals() {
1005
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
1006

    
1007
	$error = error_get_last();
1008

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

    
1022
	if (isset($FilterIfList)) {
1023
		unset($FilterIfList);
1024
	}
1025

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

    
1030
	/* Used for the hostname dns resolver */
1031
	if (isset($filterdns)) {
1032
		unset($filterdns);
1033
	}
1034

    
1035
	/* Used for aliases and interface macros */
1036
	if (isset($aliases)) {
1037
		unset($aliases);
1038
	}
1039
	if (isset($aliastable)) {
1040
		unset($aliastable);
1041
	}
1042

    
1043
	unset($config);
1044
}
1045

    
1046
register_shutdown_function('pfSense_clear_globals');
1047

    
1048
?>
(12-12/65)