Project

General

Profile

Download (27 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/config
3
 * NAME
4
 *   config.lib.inc - Functions to manipulate config.xml
5
 * DESCRIPTION
6
 *   This include contains various config.xml specific functions.
7
 * HISTORY
8
 * $Id$
9
 ******
10

    
11
	config.lib.inc
12
	Ported from config.inc by Erik Kristensen
13
	Copyright (C) 2004-2010 Scott Ullrich
14
	All rights reserved.
15

    
16
	originally part of m0n0wall (http://m0n0.ch/wall)
17
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
18
	All rights reserved.
19

    
20
	Redistribution and use in source and binary forms, with or without
21
	modification, are permitted provided that the following conditions are met:
22

    
23
	1. Redistributions of source code must retain the above copyright notice,
24
	   this list of conditions and the following disclaimer.
25

    
26
	2. Redistributions in binary form must reproduce the above copyright
27
	   notice, this list of conditions and the following disclaimer in the
28
	   documentation and/or other materials provided with the distribution.
29

    
30
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
32
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39
	POSSIBILITY OF SUCH DAMAGE.
40

    
41

    
42
	pfSense_BUILDER_BINARIES:	/sbin/mount	/sbin/sysctl	/sbin/umount	/sbin/halt	/sbin/fsck
43
	pfSense_MODULE:	config
44
*/
45

    
46
/****f* config/encrypted_configxml
47
 * NAME
48
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
49
 * INPUTS
50
 *   None
51
 * RESULT
52
 *   $config 	- rewrites config.xml without encryption
53
 ******/
54
function encrypted_configxml() {
55
	global $g, $config;
56

    
57
	if (!file_exists($g['conf_path'] . "/config.xml"))
58
		return;
59

    
60
	if (!$g['booting'])
61
		return;
62

    
63
	$configtxt = file_get_contents($g['conf_path'] . "/config.xml");			
64
	if(tagfile_deformat($configtxt, $configtxt, "config.xml")) {
65
		$fp = fopen('php://stdin', 'r');
66
		$data = "";
67
		echo "\n\n*** Encrypted config.xml detected ***\n";
68
		while($data == "") {
69
			echo "\nEnter the password to decrypt config.xml: ";
70
			$decrypt_password = chop(fgets($fp));
71
			$data = decrypt_data($configtxt, $decrypt_password);
72
			if(!strstr($data, "<pfsense>"))
73
				$data = "";
74
			if($data) {
75
				$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
76
				fwrite($fd, $data);
77
				fclose($fd);
78
				exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
79
				echo "\n" . gettext("Config.xml unlocked.") . "\n";
80
				fclose($fp);
81
			} else {
82
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
83
			}
84
		}
85
	}
86
}
87

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

    
99
	$lockkey = lock('config');
100
	$config_parsed = false;
101

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

    
114
	if($g['booting'])
115
		echo ".";
116

    
117
	// Check for encrypted config.xml
118
	encrypted_configxml();
119

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

    
157
	if($g['booting'])
158
		echo ".";
159

    
160
	$config_parsed = true;
161
	unlock($lockkey);
162

    
163
	alias_make_table($config);
164

    
165
	return $config;
166
}
167

    
168
/****f* config/generate_config_cache
169
 * NAME
170
 *   generate_config_cache - Write serialized configuration to cache.
171
 * INPUTS
172
 *   $config	- array containing current firewall configuration
173
 * RESULT
174
 *   boolean	- true on completion
175
 ******/
176
function generate_config_cache($config) {
177
	global $g, $config_extra;
178

    
179
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
180
	fwrite($configcache, serialize($config));
181
	fclose($configcache);
182
	unset($configcache);
183
	/* Used for config.extra.xml */
184
	if(file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
185
		$configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
186
		fwrite($configcacheextra, serialize($config_extra));
187
		fclose($configcacheextra);		
188
		unset($configcacheextra);
189
	}
190
}
191

    
192
function discover_last_backup() {
193
        $backups = explode("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
194
	$last_backup = "";
195
        foreach($backups as $backup)
196
        	if($backup)
197
	        	$last_backup = $backup;
198

    
199
        return $last_backup;
200
}
201

    
202
function restore_backup($file) {
203
	global $g;
204

    
205
	if (file_exists($file)) {
206
		conf_mount_rw();
207
		unlink_if_exists("{$g['tmp_path']}/config.cache");
208
		copy("$file","/cf/conf/config.xml");
209
		disable_security_checks();
210
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
211
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
212
		conf_mount_ro();
213
	}
214
}
215

    
216
/****f* config/parse_config_bootup
217
 * NAME
218
 *   parse_config_bootup - Bootup-specific configuration checks.
219
 * RESULT
220
 *   null
221
 ******/
222
function parse_config_bootup() {
223
	global $config, $g;
224

    
225
	if($g['booting'])
226
		echo ".";
227

    
228
	$lockkey = lock('config');
229
	if (!file_exists("{$g['conf_path']}/config.xml")) {
230
		if ($g['booting']) {
231
			if (strstr($g['platform'], "cdrom")) {
232
				/* try copying the default config. to the floppy */
233
				echo gettext("Resetting factory defaults...") . "\n";
234
				reset_factory_defaults(true);
235
				if (!file_exists("{$g['conf_path']}/config.xml")) {
236
					echo gettext("No XML configuration file found - using factory defaults.\n" .
237
								 "Make sure that the configuration floppy disk with the conf/config.xml\n" .
238
								 "file is inserted. If it isn't, your configuration changes will be lost\n" .
239
								 "on reboot.\n");
240
				}
241
			} else {
242
				$last_backup = discover_last_backup();
243
				if($last_backup) {
244
					log_error("No config.xml found, attempting last known config restore.");
245
					file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
246
					restore_backup("/cf/conf/backup/{$last_backup}");
247
				}
248
				if(!file_exists("{$g['conf_path']}/config.xml")) {
249
					echo sprintf(gettext("XML configuration file not found.  %s cannot continue booting."), $g['product_name']) . "\n";
250
					unlock($lockkey);
251
					mwexec("/sbin/halt");
252
					exit;
253
				}
254
				log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
255
				file_notice("config.xml", gettext("Last known config found and restored.  Please double check your configuration file for accuracy."), "pfSenseConfigurator", "");
256
			}
257
		} else {
258
			unlock($lockkey);
259
			exit(0);
260
		}
261
	}
262

    
263
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
264
		$last_backup = discover_last_backup();
265
		if($last_backup) {
266
			log_error(gettext("No config.xml found, attempting last known config restore."));
267
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
268
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
269
		} else {
270
			unlock($lockkey);
271
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
272
		}
273
	}
274
	unlock($lockkey);
275
	parse_config(true);
276

    
277
	if ((float)$config['version'] > (float)$g['latest_config']) {
278
		echo <<<EOD
279

    
280

    
281
*******************************************************************************
282
* WARNING!                                                                    *
283
* The current configuration has been created with a newer version of {$g['product_name']}  *
284
* than this one! This can lead to serious misbehavior and even security       *
285
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
286
* revert to the default configuration immediately!                            *
287
*******************************************************************************
288

    
289

    
290
EOD;
291
		}
292

    
293
	/* make alias table (for faster lookups) */
294
	alias_make_table($config);
295
}
296

    
297
/****f* config/conf_mount_rw
298
 * NAME
299
 *   conf_mount_rw - Mount filesystems read/write.
300
 * RESULT
301
 *   null
302
 ******/
303
/* mount flash card read/write */
304
function conf_mount_rw() {
305
	global $g, $config;
306

    
307
	/* do not mount on cdrom platform */
308
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
309
		return;
310

    
311
	if (!isset($config['system']['nanobsd_force_rw']) && (refcount_reference(1000) > 1))
312
		return;
313

    
314
	if (isset($config['system']['nanobsd_force_rw']) && is_writable("/"))
315
		return;
316

    
317
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
318
	if($status <> 0) {
319
		if($g['booting'])
320
			echo gettext("Disk is dirty.  Running fsck -y") . "\n";
321
		mwexec("/sbin/fsck -y {$g['cf_path']}");
322
		$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
323
	}
324

    
325
	/*    if the platform is soekris or wrap or pfSense, lets mount the
326
	 *    compact flash cards root.
327
         */
328
	$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
329
	/* we could not mount this correctly.  kick off fsck */
330
	if($status <> 0) {
331
		log_error(gettext("File system is dirty.  Launching FSCK for /"));
332
		mwexec("/sbin/fsck -y /");
333
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
334
	}
335
	
336
	mark_subsystem_dirty('mount');
337
}
338

    
339
/****f* config/conf_mount_ro
340
 * NAME
341
 *   conf_mount_ro - Mount filesystems readonly.
342
 * RESULT
343
 *   null
344
 ******/
345
function conf_mount_ro() {
346
	global $g, $config;
347

    
348
	/* Do not trust $g['platform'] since this can be clobbered during factory reset. */
349
	$platform = trim(file_get_contents("/etc/platform"));
350
	/* do not umount on cdrom or pfSense platforms */
351
	if($platform == "cdrom" or $platform == "pfSense" or isset($config['system']['nanobsd_force_rw']))
352
		return;
353

    
354
	if (refcount_unreference(1000) > 0)
355
		return;
356

    
357
	if($g['booting'])
358
		return;
359

    
360
	clear_subsystem_dirty('mount');
361
	/* sync data, then force a remount of /cf */
362
	pfSense_sync();
363
	mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
364
	mwexec("/sbin/mount -u -r -f -o sync,noatime /");
365
}
366

    
367
/****f* config/convert_config
368
 * NAME
369
 *   convert_config - Attempt to update config.xml.
370
 * DESCRIPTION
371
 *   convert_config() reads the current global configuration
372
 *   and attempts to convert it to conform to the latest
373
 *   config.xml version. This allows major formatting changes
374
 *   to be made with a minimum of breakage.
375
 * RESULT
376
 *   null
377
 ******/
378
/* convert configuration, if necessary */
379
function convert_config() {
380
	global $config, $g;
381
	$now = date("H:i:s");
382
	log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
383
	//ini_set("max_execution_time", "900");
384

    
385
	/* special case upgrades */
386
	/* fix every minute crontab bogons entry */
387
	$cron_item_count = count($config['cron']['item']);
388
	for($x=0; $x<$cron_item_count; $x++) {
389
		if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
390
			if($config['cron']['item'][$x]['hour'] == "*" ) {
391
		        $config['cron']['item'][$x]['hour'] = "3";
392
		 		write_config(gettext("Updated bogon update frequency to 3am"));
393
		 		log_error(gettext("Updated bogon update frequency to 3am"));
394
		 	}       
395
		}
396
	}
397
	if ($config['version'] == $g['latest_config'])
398
		return;		/* already at latest version */
399

    
400
	// Save off config version
401
	$prev_version = $config['version'];
402
	
403
	include_once('auth.inc');
404
	include_once('upgrade_config.inc');
405
	if (file_exists("/etc/inc/upgrade_config_custom.inc"))
406
		include_once("upgrade_config_custom.inc");
407
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
408
	while ($config['version'] < $g['latest_config']) {
409
		$cur = $config['version'] * 10;
410
		$next = $cur + 1;
411
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
412
		if (function_exists($migration_function))
413
			$migration_function();
414
		$migration_function = "{$migration_function}_custom";
415
		if (function_exists($migration_function))
416
			$migration_function();
417
		$config['version'] = sprintf('%.1f', $next / 10);
418
		if($g['booting'])
419
			echo ".";
420
	}
421

    
422
	$now = date("H:i:s");
423
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
424

    
425
	if ($prev_version != $config['version'])
426
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
427
}
428

    
429
/****f* config/safe_write_file
430
 * NAME
431
 *   safe_write_file - Write a file out atomically
432
 * DESCRIPTION
433
 *   safe_write_file() Writes a file out atomically by first writing to a
434
 *   temporary file of the same name but ending with the pid of the current
435
 *   process, them renaming the temporary file over the original.
436
 * INPUTS
437
 *   $filename  - string containing the filename of the file to write
438
 *   $content   - string containing the file content to write to file
439
 *   $force_binary      - boolean denoting whether we should force binary
440
 *   mode writing.
441
 * RESULT
442
 *   boolean - true if successful, false if not
443
 ******/
444
function safe_write_file($file, $content, $force_binary) {
445
	$tmp_file = $file . "." . getmypid();
446
	$write_mode = $force_binary ? "wb" : "w";
447

    
448
	$fd = fopen($tmp_file, $write_mode);
449
	if (!$fd) {
450
		// Unable to open temporary file for writing
451
		return false;
452
        }
453
	if (!fwrite($fd, $content)) {
454
		// Unable to write to temporary file
455
		fclose($fd);
456
		return false;
457
	}
458
	fflush($fd);
459
	fclose($fd);
460

    
461
	if (!rename($tmp_file, $file)) {
462
		// Unable to move temporary file to original
463
		@unlink($tmp_file);
464
		return false;
465
	}
466

    
467
	// Sync file before returning
468
	pfSense_sync();
469

    
470
	return true;
471
}
472

    
473
/****f* config/write_config
474
 * NAME
475
 *   write_config - Backup and write the firewall configuration.
476
 * DESCRIPTION
477
 *   write_config() handles backing up the current configuration,
478
 *   applying changes, and regenerating the configuration cache.
479
 * INPUTS
480
 *   $desc	- string containing the a description of configuration changes
481
 *   $backup	- boolean: do not back up current configuration if false.
482
 * RESULT
483
 *   null
484
 ******/
485
/* save the system configuration */
486
function write_config($desc="Unknown", $backup = true) {
487
	global $config, $g;
488

    
489
	/* TODO: Not sure what this was added for; commenting out
490
	 *       for now, since it was preventing config saving. */
491
	// $config = parse_config(true, false, false);
492
	
493
	/* Comment this check out for now. There aren't any current issues that
494
	 *   make this problematic, and it makes users think there is a problem
495
	 *   when one doesn't really exist.
496
	if($g['booting'])
497
		log_error("WARNING! Configuration written on bootup.  This can cause stray openvpn and load balancing items in config.xml");
498
	*/
499

    
500
	if (!empty($_SERVER['REMOTE_ADDR'])) {
501
		if (!session_id())
502
			@session_start();
503
		if (!empty($_SESSION['Username']) && ($_SESSION['Username'] != "admin")) {
504
			$user = getUserEntry($_SESSION['Username']);
505
			if (is_array($user) && userHasPrivilege($user, "user-config-readonly")) {
506
				session_commit();
507
				return false;
508
			}
509
		}
510
	}
511

    
512
	if (empty($_SESSION["Username"])) {
513
		if (empty($_ENV['USER']) || $_ENV['USER'] == "root")
514
			$username = "(system)";
515
		else
516
			$username = $_ENV['USER'];
517
	} else
518
		$username = $_SESSION["Username"];
519

    
520
	if (!empty($_SERVER['REMOTE_ADDR']))
521
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
522

    
523
	if (!isset($argc))
524
		session_commit();
525

    
526
	if($backup)
527
		backup_config();
528

    
529
	if (!is_array($config['revision']))
530
		$config['revision'] = array();
531

    
532
	if (time() > mktime(0, 0, 0, 9, 1, 2004))       /* make sure the clock settings are plausible */
533
		$config['revision']['time'] = time();
534

    
535
	/* Log the running script so it's not entirely unlogged what changed */
536
	if ($desc == "Unknown")
537
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
538

    
539
	$config['revision']['description'] = "{$username}: " . $desc;
540
	$config['revision']['username'] = $username;
541

    
542
	conf_mount_rw();
543
	$lockkey = lock('config', LOCK_EX);
544

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

    
548
	/* write new configuration */
549
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
550
		log_error(gettext("WARNING: Config contents could not be save. Could not open file!"));
551
		unlock($lockkey);
552
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
553
		return -1;
554
	}
555
	
556
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
557
		cleanup_backupcache(5, true);
558
	} else {
559
		cleanup_backupcache(30, true);
560
	}
561

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

    
581
	unlock($lockkey);
582

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

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

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

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

    
596
	return $config;
597
}
598

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

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

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

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

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

    
627
	disable_security_checks();
628

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

    
638
function config_restore($conffile) {
639
	global $config, $g;
640

    
641
	if (!file_exists($conffile))
642
		return 1;
643

    
644
	backup_config();
645

    
646
	conf_mount_rw();
647
	
648
	$lockkey = lock('config', LOCK_EX);
649

    
650
	unlink_if_exists("{$g['tmp_path']}/config.cache");
651
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
652

    
653
	disable_security_checks();
654

    
655
	unlock($lockkey);
656

    
657
	$config = parse_config(true);
658

    
659
	conf_mount_ro();
660

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

    
663
	return 0;
664
}
665

    
666
function config_install($conffile) {
667
	global $config, $g;
668

    
669
	if (!file_exists($conffile))
670
		return 1;
671

    
672
	if (!config_validate("{$conffile}"))
673
		return 1;
674

    
675
	if($g['booting'] == true)
676
		echo gettext("Installing configuration...") . "\n";
677
	else
678
		log_error(gettext("Installing configuration ...."));
679

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

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

    
685
	disable_security_checks();
686

    
687
	/* unlink cache file if it exists */
688
	if(file_exists("{$g['tmp_path']}/config.cache"))
689
		unlink("{$g['tmp_path']}/config.cache");
690

    
691
	unlock($lockkey);
692
	conf_mount_ro();
693

    
694
    return 0;
695
}
696

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

    
710
/* Restores security checks.  Should be called after all succeed. */
711
function restore_security_checks() {
712
	global $g;
713
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
714
}
715

    
716
/* Returns status of security check temporary disable. */
717
function security_checks_disabled() {
718
	global $g;
719
	return file_exists("{$g['tmp_path']}/disable_security_checks");
720
}
721

    
722
function config_validate($conffile) {
723

    
724
	global $g, $xmlerr;
725

    
726
	$xml_parser = xml_parser_create();
727

    
728
	if (!($fp = fopen($conffile, "r"))) {
729
		$xmlerr = gettext("XML error: unable to open file");
730
		return false;
731
	}
732

    
733
	while ($data = fread($fp, 4096)) {
734
		if (!xml_parse($xml_parser, $data, feof($fp))) {
735
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
736
						xml_error_string(xml_get_error_code($xml_parser)),
737
						xml_get_current_line_number($xml_parser));
738
			return false;
739
		}
740
	}
741
	xml_parser_free($xml_parser);
742

    
743
	fclose($fp);
744

    
745
	return true;
746
}
747

    
748
function cleanup_backupcache($revisions = 30, $lock = false) {
749
	global $g;
750
	$i = false;
751
	
752
	if (!$lock)
753
		$lockkey = lock('config');
754

    
755
	conf_mount_rw();
756

    
757
	$backups = get_backups();
758
	if ($backups) {
759
		$baktimes = $backups['versions'];
760
		unset($backups['versions']);
761
	} else {
762
		$backups = array();
763
		$baktimes = array();
764
	}
765
	$newbaks = array();
766
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
767
	$tocache = array();
768

    
769
	foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
770
		if(filesize($backup) == 0) {
771
			unlink($backup);
772
			continue;
773
		}
774
		$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
775
		if(!in_array($tocheck, $baktimes)) {
776
			$i = true;
777
			if($g['booting'])
778
				echo ".";
779
			$newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
780
			if($newxml == "-1") {
781
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
782
				unlink($backup);
783
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
784
				continue;
785
			}
786
			if($newxml['revision']['description'] == "")
787
				$newxml['revision']['description'] = "Unknown";
788
			if($newxml['version'] == "")
789
				$newxml['version'] = "?";
790
			$tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version']);
791
		}
792
	}
793
	foreach($backups as $checkbak) {
794
		if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
795
			$newbaks[] = $checkbak;
796
		} else {
797
			$i = true;
798
			if($g['booting']) print " " . $tocheck . "r";
799
		}
800
	}
801
	foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version']);
802
	if(is_int($revisions) and (count($tocache) > $revisions)) {
803
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
804
		foreach($toslice as $sliced)
805
			$newcache[$sliced] = $tocache[$sliced];
806
		foreach($tocache as $version => $versioninfo) {
807
			if(!in_array($version, array_keys($newcache))) {
808
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
809
				//if($g['booting']) print " " . $tocheck . "d";
810
			}
811
		}
812
		$tocache = $newcache;
813
	}
814
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
815
	fwrite($bakout, serialize($tocache));
816
	fclose($bakout);
817
	conf_mount_ro();
818

    
819
	if (!$lock)
820
		unlock($lockkey);
821
}
822

    
823
function get_backups() {
824
	global $g;
825
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
826
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
827
		$bakvers = array_keys($confvers);
828
		$toreturn = array();
829
		sort($bakvers);
830
		// 	$bakvers = array_reverse($bakvers);
831
		foreach(array_reverse($bakvers) as $bakver)
832
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version']);
833
	} else {
834
		return false;
835
	}
836
	$toreturn['versions'] = $bakvers;
837
	return $toreturn;
838
}
839

    
840
function backup_config() {
841
	global $config, $g;
842

    
843
	if($g['platform'] == "cdrom")
844
		return;
845

    
846
	conf_mount_rw();
847

    
848
	/* Create backup directory if needed */
849
	safe_mkdir("{$g['cf_conf_path']}/backup");
850

    
851
    if($config['revision']['time'] == "") {
852
            $baktime = 0;
853
    } else {
854
            $baktime = $config['revision']['time'];
855
    }
856
    if($config['revision']['description'] == "") {
857
            $bakdesc = "Unknown";
858
    } else {
859
            $bakdesc = $config['revision']['description'];
860
    }
861

    
862
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
863

    
864
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
865
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
866
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
867
    } else {
868
            $backupcache = array();
869
    }
870
    $backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver);
871
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
872
    fwrite($bakout, serialize($backupcache));
873
    fclose($bakout);
874

    
875
	conf_mount_ro();
876

    
877
	return true;
878
}
879

    
880
function set_device_perms() {
881
	$devices = array(
882
		'pf'	=> array(	'user'	=> 'root',
883
					'group'	=> 'proxy',
884
					'mode'	=> 0660),
885
		);
886

    
887
	foreach ($devices as $name => $attr) {
888
		$path = "/dev/$name";
889
		if (file_exists($path)) {
890
			chown($path, $attr['user']);
891
			chgrp($path, $attr['group']);
892
			chmod($path, $attr['mode']);
893
		}
894
	}
895
}
896

    
897
?>
(13-13/66)