Project

General

Profile

Download (26.3 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;
306

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

    
311
	if (refcount_reference(1000) > 1)
312
		return;
313

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

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

    
336
/****f* config/conf_mount_ro
337
 * NAME
338
 *   conf_mount_ro - Mount filesystems readonly.
339
 * RESULT
340
 *   null
341
 ******/
342
function conf_mount_ro() {
343
	global $g;
344

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

    
351
	if (refcount_unreference(1000) > 0)
352
		return;
353

    
354
	if($g['booting'])
355
		return;
356

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

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

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

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

    
419
	$now = date("H:i:s");
420
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
421

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

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

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

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

    
464
	// Sync file before returning
465
	pfSense_sync();
466

    
467
	return true;
468
}
469

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

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

    
497
	$username = empty($_SESSION["Username"]) ? "(system)" : $_SESSION['Username'];
498
	if (!empty($_SERVER['REMOTE_ADDR']))
499
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
500

    
501
	if($backup)
502
		backup_config();
503

    
504
	if (!is_array($config['revision']))
505
		$config['revision'] = array();
506

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

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

    
514
	$config['revision']['description'] = "{$username}: " . $desc;
515
	$config['revision']['username'] = $username;
516

    
517
	conf_mount_rw();
518
	$lockkey = lock('config', LOCK_EX);
519

    
520
	/* generate configuration XML */
521
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
522

    
523
	/* write new configuration */
524
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
525
		log_error(gettext("WARNING: Config contents could not be save. Could not open file!"));
526
		unlock($lockkey);
527
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
528
		return -1;
529
	}
530
	
531
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
532
		cleanup_backupcache(5, true);
533
	} else {
534
		cleanup_backupcache(30, true);
535
	}
536

    
537
	/* re-read configuration */
538
	/* NOTE: We assume that the file can be parsed since we wrote it. */
539
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
540
	if ($config == -1) {
541
		copy("{$g['conf_path']}/config.xml", "{$g['conf_path']}/config.xml.bad");
542
		$last_backup = discover_last_backup();
543
		if ($last_backup) {
544
			restore_backup("/cf/conf/backup/{$last_backup}");
545
			$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
546
			if ($g['booting']) {
547
				echo "\n\n ************** WARNING **************";
548
				echo "\n\n Configuration could not be validated. A previous configuration was restored. \n";
549
				echo "\n The failed configuration file has been saved as {$g['conf_path']}/config.xml.bad} \n\n";
550
			}
551
		} else
552
			log_error(gettext("Could not restore config.xml."));
553
	} else
554
		generate_config_cache($config);
555

    
556
	unlock($lockkey);
557

    
558
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
559

    
560
	/* tell kernel to sync fs data */
561
	conf_mount_ro();
562

    
563
	/* sync carp entries to other firewalls */
564
	carp_sync_client();
565

    
566
	if(is_dir("/usr/local/pkg/write_config")) {
567
		/* process packager manager custom rules */
568
		run_plugins("/usr/local/pkg/write_config/");
569
	}
570

    
571
	return $config;
572
}
573

    
574
/****f* config/reset_factory_defaults
575
 * NAME
576
 *   reset_factory_defaults - Reset the system to its default configuration.
577
 * RESULT
578
 *   integer	- indicates completion
579
 ******/
580
function reset_factory_defaults($lock = false) {
581
	global $g;
582

    
583
	conf_mount_rw();
584
	if (!$lock)
585
		$lockkey = lock('config', LOCK_EX);
586

    
587
	/* create conf directory, if necessary */
588
	safe_mkdir("{$g['cf_conf_path']}");
589

    
590
	/* clear out /conf */
591
	$dh = opendir($g['conf_path']);
592
	while ($filename = readdir($dh)) {
593
		if (($filename != ".") && ($filename != "..")) {
594
			unlink_if_exists($g['conf_path'] . "/" . $filename);
595
		}
596
	}
597
	closedir($dh);
598

    
599
	/* copy default configuration */
600
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
601

    
602
	disable_security_checks();
603

    
604
	/* call the wizard */
605
	touch("/conf/trigger_initial_wizard");
606
	if (!$lock)
607
		unlock($lockkey);
608
	conf_mount_ro();
609
	setup_serial_port();
610
	return 0;
611
}
612

    
613
function config_restore($conffile) {
614
	global $config, $g;
615

    
616
	if (!file_exists($conffile))
617
		return 1;
618

    
619
	backup_config();
620

    
621
	conf_mount_rw();
622
	
623
	$lockkey = lock('config', LOCK_EX);
624

    
625
	unlink_if_exists("{$g['tmp_path']}/config.cache");
626
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
627

    
628
	disable_security_checks();
629

    
630
	unlock($lockkey);
631

    
632
	$config = parse_config(true);
633

    
634
	conf_mount_ro();
635

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

    
638
	return 0;
639
}
640

    
641
function config_install($conffile) {
642
	global $config, $g;
643

    
644
	if (!file_exists($conffile))
645
		return 1;
646

    
647
	if (!config_validate("{$conffile}"))
648
		return 1;
649

    
650
	if($g['booting'] == true)
651
		echo gettext("Installing configuration...") . "\n";
652
	else
653
		log_error(gettext("Installing configuration ...."));
654

    
655
	conf_mount_rw();
656
	$lockkey = lock('config', LOCK_EX);
657

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

    
660
	disable_security_checks();
661

    
662
	/* unlink cache file if it exists */
663
	if(file_exists("{$g['tmp_path']}/config.cache"))
664
		unlink("{$g['tmp_path']}/config.cache");
665

    
666
	unlock($lockkey);
667
	conf_mount_ro();
668

    
669
    return 0;
670
}
671

    
672
/*
673
 * Disable security checks for DNS rebind and HTTP referrer until next time
674
 * they pass (or reboot), to aid in preventing accidental lockout when
675
 * restoring settings like hostname, domain, IP addresses, and settings
676
 * related to the DNS rebind and HTTP referrer checks.
677
 * Intended for use when restoring a configuration or directly
678
 * modifying config.xml without an unconditional reboot.
679
 */
680
function disable_security_checks() {
681
	global $g;
682
	touch("{$g['tmp_path']}/disable_security_checks");
683
}
684

    
685
/* Restores security checks.  Should be called after all succeed. */
686
function restore_security_checks() {
687
	global $g;
688
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
689
}
690

    
691
/* Returns status of security check temporary disable. */
692
function security_checks_disabled() {
693
	global $g;
694
	return file_exists("{$g['tmp_path']}/disable_security_checks");
695
}
696

    
697
function config_validate($conffile) {
698

    
699
	global $g, $xmlerr;
700

    
701
	$xml_parser = xml_parser_create();
702

    
703
	if (!($fp = fopen($conffile, "r"))) {
704
		$xmlerr = gettext("XML error: unable to open file");
705
		return false;
706
	}
707

    
708
	while ($data = fread($fp, 4096)) {
709
		if (!xml_parse($xml_parser, $data, feof($fp))) {
710
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
711
						xml_error_string(xml_get_error_code($xml_parser)),
712
						xml_get_current_line_number($xml_parser));
713
			return false;
714
		}
715
	}
716
	xml_parser_free($xml_parser);
717

    
718
	fclose($fp);
719

    
720
	return true;
721
}
722

    
723
function cleanup_backupcache($revisions = 30, $lock = false) {
724
	global $g;
725
	$i = false;
726
	
727
	if (!$lock)
728
		$lockkey = lock('config');
729

    
730
	conf_mount_rw();
731

    
732
	$backups = get_backups();
733
	if ($backups) {
734
		$baktimes = $backups['versions'];
735
		unset($backups['versions']);
736
	} else {
737
		$backups = array();
738
		$baktimes = array();
739
	}
740
	$newbaks = array();
741
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
742
	$tocache = array();
743

    
744
	foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
745
		if(filesize($backup) == 0) {
746
			unlink($backup);
747
			continue;
748
		}
749
		$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
750
		if(!in_array($tocheck, $baktimes)) {
751
			$i = true;
752
			if($g['booting'])
753
				echo ".";
754
			$newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
755
			if($newxml == "-1") {
756
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
757
				unlink($backup);
758
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
759
				continue;
760
			}
761
			if($newxml['revision']['description'] == "")
762
				$newxml['revision']['description'] = "Unknown";
763
			if($newxml['version'] == "")
764
				$newxml['version'] = "?";
765
			$tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version']);
766
		}
767
	}
768
	foreach($backups as $checkbak) {
769
		if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
770
			$newbaks[] = $checkbak;
771
		} else {
772
			$i = true;
773
			if($g['booting']) print " " . $tocheck . "r";
774
		}
775
	}
776
	foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version']);
777
	if(is_int($revisions) and (count($tocache) > $revisions)) {
778
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
779
		foreach($toslice as $sliced)
780
			$newcache[$sliced] = $tocache[$sliced];
781
		foreach($tocache as $version => $versioninfo) {
782
			if(!in_array($version, array_keys($newcache))) {
783
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
784
				//if($g['booting']) print " " . $tocheck . "d";
785
			}
786
		}
787
		$tocache = $newcache;
788
	}
789
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
790
	fwrite($bakout, serialize($tocache));
791
	fclose($bakout);
792
	conf_mount_ro();
793

    
794
	if (!$lock)
795
		unlock($lockkey);
796
}
797

    
798
function get_backups() {
799
	global $g;
800
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
801
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
802
		$bakvers = array_keys($confvers);
803
		$toreturn = array();
804
		sort($bakvers);
805
		// 	$bakvers = array_reverse($bakvers);
806
		foreach(array_reverse($bakvers) as $bakver)
807
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version']);
808
	} else {
809
		return false;
810
	}
811
	$toreturn['versions'] = $bakvers;
812
	return $toreturn;
813
}
814

    
815
function backup_config() {
816
	global $config, $g;
817

    
818
	if($g['platform'] == "cdrom")
819
		return;
820

    
821
	conf_mount_rw();
822

    
823
	/* Create backup directory if needed */
824
	safe_mkdir("{$g['cf_conf_path']}/backup");
825

    
826
    if($config['revision']['time'] == "") {
827
            $baktime = 0;
828
    } else {
829
            $baktime = $config['revision']['time'];
830
    }
831
    if($config['revision']['description'] == "") {
832
            $bakdesc = "Unknown";
833
    } else {
834
            $bakdesc = $config['revision']['description'];
835
    }
836

    
837
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
838

    
839
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
840
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
841
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
842
    } else {
843
            $backupcache = array();
844
    }
845
    $backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver);
846
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
847
    fwrite($bakout, serialize($backupcache));
848
    fclose($bakout);
849

    
850
	conf_mount_ro();
851

    
852
	return true;
853
}
854

    
855
function set_device_perms() {
856
	$devices = array(
857
		'pf'	=> array(	'user'	=> 'root',
858
					'group'	=> 'proxy',
859
					'mode'	=> 0660),
860
		);
861

    
862
	foreach ($devices as $name => $attr) {
863
		$path = "/dev/$name";
864
		if (file_exists($path)) {
865
			chown($path, $attr['user']);
866
			chgrp($path, $attr['group']);
867
			chmod($path, $attr['mode']);
868
		}
869
	}
870
}
871

    
872
?>
(14-14/65)