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
	conf_mount_rw();
628

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

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

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

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

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

    
655
	disable_security_checks();
656

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

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

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

    
679
	backup_config();
680

    
681
	conf_mount_rw();
682

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

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

    
688
	disable_security_checks();
689

    
690
	unlock($lockkey);
691

    
692
	$config = parse_config(true);
693

    
694
	conf_mount_ro();
695

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

    
698
	return 0;
699
}
700

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

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

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

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

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

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

    
723
	disable_security_checks();
724

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

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

    
733
	return 0;
734
}
735

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

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

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

    
761
function config_validate($conffile) {
762

    
763
	global $g, $xmlerr;
764

    
765
	$xml_parser = xml_parser_create();
766

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

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

    
782
	fclose($fp);
783

    
784
	return true;
785
}
786

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

    
791
	$revisions = get_config_backup_count();
792

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

    
797
	conf_mount_rw();
798

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

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

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

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

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

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

    
901
	conf_mount_rw();
902

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

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

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

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

    
932
	conf_mount_ro();
933

    
934
	return true;
935
}
936

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

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

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

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

    
969
	return $username;
970
}
971

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

    
979
	$revision = array();
980

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

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

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

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

    
1010
	$error = error_get_last();
1011

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

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

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

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

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

    
1046
	unset($config);
1047
}
1048

    
1049
register_shutdown_function('pfSense_clear_globals');
1050

    
1051
?>
(12-12/65)