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_array($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, the 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 the configuration file for accuracy.");
287
				file_notice("config.xml", gettext("Last known config found and restored.  Please double check the 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 nothing here. redmine #6184
381
	return;
382

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

    
390
	if (refcount_unreference(1000) > 0) {
391
		return;
392
	}
393

    
394
	if (isset($config['system']['nanobsd_force_rw'])) {
395
		return;
396
	}
397

    
398
	if (platform_booting()) {
399
		return;
400
	}
401

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

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

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

    
445
	// Save off config version
446
	$prev_version = $config['version'];
447

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

    
471
	$now = date("H:i:s");
472
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
473

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

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

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

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

    
517
	// Sync file before returning
518
	return pfSense_fsync($file);
519
}
520

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

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

    
551
	if (!isset($argc)) {
552
		session_commit();
553
	}
554

    
555
	if ($backup) {
556
		backup_config();
557
	}
558

    
559
	$config['revision'] = make_config_revision_entry($desc);
560

    
561
	conf_mount_rw();
562
	$lockkey = lock('config', LOCK_EX);
563

    
564
	/* generate configuration XML */
565
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
566

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

    
575
	cleanup_backupcache(true);
576

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

    
598
	unlock($lockkey);
599

    
600
	if ($write_config_only) {
601
		/* tell kernel to sync fs data */
602
		conf_mount_ro();
603
		return $config;
604
	}
605

    
606
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
607

    
608
	/* tell kernel to sync fs data */
609
	conf_mount_ro();
610

    
611
	/* sync carp entries to other firewalls */
612
	carp_sync_client();
613

    
614
	if (is_dir("/usr/local/pkg/write_config")) {
615
		/* process packager manager custom rules */
616
		run_plugins("/usr/local/pkg/write_config/");
617
	}
618

    
619
	return $config;
620
}
621

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

    
631
	conf_mount_rw();
632

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

    
637
	if (!$lock) {
638
		$lockkey = lock('config', LOCK_EX);
639
	}
640

    
641
	/* create conf directory, if necessary */
642
	safe_mkdir($g['cf_conf_path']);
643

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

    
655
	/* copy default configuration */
656
	copy("{$g['conf_default_path']}/config.xml",
657
	    "{$g['cf_conf_path']}/config.xml");
658

    
659
	disable_security_checks();
660

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

    
676
function config_restore($conffile) {
677
	global $config, $g;
678

    
679
	if (!file_exists($conffile)) {
680
		return 1;
681
	}
682

    
683
	backup_config();
684

    
685
	conf_mount_rw();
686

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

    
689
	unlink_if_exists("{$g['tmp_path']}/config.cache");
690
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
691

    
692
	disable_security_checks();
693

    
694
	unlock($lockkey);
695

    
696
	$config = parse_config(true);
697

    
698
	conf_mount_ro();
699

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

    
702
	return 0;
703
}
704

    
705
function config_install($conffile) {
706
	global $config, $g;
707

    
708
	if (!file_exists($conffile)) {
709
		return 1;
710
	}
711

    
712
	if (!config_validate("{$conffile}")) {
713
		return 1;
714
	}
715

    
716
	if (platform_booting()) {
717
		echo gettext("Installing configuration...") . "\n";
718
	} else {
719
		log_error(gettext("Installing configuration ...."));
720
	}
721

    
722
	conf_mount_rw();
723
	$lockkey = lock('config', LOCK_EX);
724

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

    
727
	disable_security_checks();
728

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

    
734
	unlock($lockkey);
735
	conf_mount_ro();
736

    
737
	return 0;
738
}
739

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

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

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

    
765
function config_validate($conffile) {
766

    
767
	global $g, $xmlerr;
768

    
769
	$xml_parser = xml_parser_create();
770

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

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

    
786
	fclose($fp);
787

    
788
	return true;
789
}
790

    
791
function cleanup_backupcache($lock = false) {
792
	global $g;
793
	$i = false;
794

    
795
	$revisions = intval(is_numericint($config['system']['backupcount']) ? $config['system']['backupcount'] : $g['default_config_backup_count']);
796

    
797
	if (!$lock) {
798
		$lockkey = lock('config');
799
	}
800

    
801
	conf_mount_rw();
802

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

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

    
875
	if (!$lock) {
876
		unlock($lockkey);
877
	}
878
}
879

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

    
898
function backup_config() {
899
	global $config, $g;
900

    
901
	if ($g['platform'] == "cdrom") {
902
		return;
903
	}
904

    
905
	conf_mount_rw();
906

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

    
915
	if ($config['revision']['description'] == "") {
916
		$bakdesc = "Unknown";
917
	} else {
918
		$bakdesc = $config['revision']['description'];
919
	}
920

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

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

    
936
	conf_mount_ro();
937

    
938
	return true;
939
}
940

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

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

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

    
969
	if (!empty($_SERVER['REMOTE_ADDR'])) {
970
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
971
	}
972

    
973
	return $username;
974
}
975

    
976
function make_config_revision_entry($desc = null, $override_user = null) {
977
	if (empty($override_user)) {
978
		$username = get_config_user();
979
	} else {
980
		$username = $override_user;
981
	}
982

    
983
	$revision = array();
984

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

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

    
1000
function pfSense_clear_globals() {
1001
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
1002

    
1003
	$error = error_get_last();
1004

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

    
1018
	if (isset($FilterIfList)) {
1019
		unset($FilterIfList);
1020
	}
1021

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

    
1026
	/* Used for the hostname dns resolver */
1027
	if (isset($filterdns)) {
1028
		unset($filterdns);
1029
	}
1030

    
1031
	/* Used for aliases and interface macros */
1032
	if (isset($aliases)) {
1033
		unset($aliases);
1034
	}
1035
	if (isset($aliastable)) {
1036
		unset($aliastable);
1037
	}
1038

    
1039
	unset($config);
1040
}
1041

    
1042
register_shutdown_function('pfSense_clear_globals');
1043

    
1044
?>
(12-12/65)