Project

General

Profile

Download (24.1 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	/bin/sync
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
	if(file_exists($g['conf_path'] . "/config.xml")) {
57
		if($g['booting']) {
58
			$configtxt = file_get_contents($g['conf_path'] . "/config.xml");			
59
			if(tagfile_deformat($configtxt, $configtxt, "config.xml")) {
60
				$fp = fopen('php://stdin', 'r');
61
				$data = "";
62
				echo "\n\n*** Encrypted config.xml detected ***\n";
63
				while($data == "") {
64
					echo "\nEnter the password to decrypt config.xml: ";
65
					$decrypt_password = chop(fgets($fp));
66
					$data = decrypt_data($configtxt, $decrypt_password);
67
					if(!strstr($data, "<pfsense>"))
68
						$data = "";
69
					if($data) {
70
						$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
71
						fwrite($fd, $data);
72
						fclose($fd);
73
						exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
74
						echo "\nConfig.xml unlocked.\n";
75
						fclose($fp);
76
					} else {
77
						echo "\nInvalid password entered.  Please try again.\n";
78
					}
79
				}
80
			}
81
		}
82
	}
83
}
84

    
85
/****f* config/parse_config
86
 * NAME
87
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
88
 * INPUTS
89
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
90
 * RESULT
91
 *   $config      - array containing all configuration variables
92
 ******/
93
function parse_config($parse = false) {
94
	global $g, $config_parsed, $config_extra;
95
	
96
	$lockkey = lock('config');
97
	$config_parsed = false;
98
	if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
99
		$last_backup = discover_last_backup();
100
		if($last_backup) {
101
			log_error("No config.xml found, attempting last known config restore.");
102
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
103
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
104
		} else {
105
			unlock($lockkey);
106
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
107
		}
108
	}
109
	if($g['booting']) echo ".";
110
	// Check for encrypted config.xml
111
	encrypted_configxml();
112
	if(!$parse) {
113
		if(file_exists($g['tmp_path'] . '/config.cache')) {
114
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
115
			if(is_null($config)) {
116
				unlock($lockkey);
117
				parse_config(true);
118
				$lockkey = lock('config');
119
			}
120
		} else {
121
			if(!file_exists($g['conf_path'] . "/config.xml")) {
122
				log_error("No config.xml found, attempting last known config restore.");
123
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
124
				$last_backup = discover_last_backup();
125
				if ($last_backup)
126
					restore_backup("/cf/conf/backup/{$last_backup}");
127
				else {
128
					log_error("Could not restore config.xml.");
129
					unlock($lockkey);
130
					die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
131
				}
132
			}
133
			unlock($lockkey);
134
			$config = parse_config(true);
135
			$lockkey = lock('config');
136
		}
137
	} else {
138
		if(!file_exists($g['conf_path'] . "/config.xml")) {
139
			if($g['booting']) echo ".";
140
			log_error("No config.xml found, attempting last known config restore.");
141
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
142
			$last_backup = discover_last_backup();
143
			if ($last_backup)
144
				restore_backup("/cf/conf/backup/{$last_backup}");
145
			else {
146
				log_error("Could not restore config.xml.");
147
				unlock($lockkey);
148
				die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
149
			}
150
		}
151
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
152
		if($config == "-1") {
153
			$last_backup = discover_last_backup();
154
			if ($last_backup)
155
				restore_backup("/cf/conf/backup/{$last_backup}");
156
			else {
157
				log_error(gettext("Could not restore config.xml."));
158
				unlock($lockkey);
159
				die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
160
			}
161
		}
162
		generate_config_cache($config);
163
	}
164
	if($g['booting']) echo ".";
165
	alias_make_table($config);
166
	$config_parsed = true;
167
	unlock($lockkey);
168

    
169
	return $config;
170
}
171

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

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

    
196
function discover_last_backup() {
197
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
198
	$last_backup = "";
199
        foreach($backups as $backup)
200
        	if($backup)
201
	        	$last_backup = $backup;
202

    
203
        return $last_backup;
204
}
205

    
206
function restore_backup($file) {
207
	global $g;
208

    
209
	if (file_exists($file)) {
210
		conf_mount_rw();
211
		unlink_if_exists("{$g['tmp_path']}/config.cache");
212
		copy("$file","/cf/conf/config.xml");
213
		log_error("{$g['product_name']} is restoring the configuration $file");
214
		file_notice("config.xml", "{$g['product_name']} is restoring the configuration $file", "pfSenseConfigurator", "");
215
		conf_mount_ro();
216
	}
217
}
218

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

    
228
	if($g['booting']) echo ".";
229

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

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

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

    
281

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

    
290

    
291
EOD;
292
		}
293

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

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

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

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

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

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

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

    
346
	/* do not umount on cdrom or pfSense platforms */
347
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
348
		return;
349

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

    
353
	clear_subsystem_dirty('mount');
354
	/* sync data, then force a remount of /cf */
355
	mwexec("/bin/sync; /bin/sync");
356
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
357
	mwexec("/sbin/mount -u -r -f /");
358
}
359

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

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

    
393
	// Save off config version
394
	$prev_version = $config['version'];
395
	
396
	include_once('auth.inc');
397
	include_once('upgrade_config.inc');
398
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
399
	while ($config['version'] < $g['latest_config']) {
400
		$cur = $config['version'] * 10;
401
		$next = $cur + 1;
402
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
403
		$migration_function();
404
		$config['version'] = sprintf('%.1f', $next / 10);
405
		if($g['booting'])
406
			echo ".";
407
	}
408

    
409
	$now = date("H:i:s");
410
	log_error("Ended Configuration upgrade at $now");
411

    
412
	if ($prev_version != $config['version'])
413
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
414

    
415
	if($g['booting'])
416
		echo "Loading new configuration...";
417
}
418

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

    
438
        $fd = fopen($tmp_file, $write_mode);
439
        if (!$fd) {
440
                // Unable to open temporary file for writing
441
                return false;
442
        }
443
        if (!fwrite($fd, $content)) {
444
                // Unable to write to temporary file
445
                fclose($fd);
446
                return false;
447
        }
448
        fclose($fd);
449

    
450
        if (!rename($tmp_file, $file)) {
451
                // Unable to move temporary file to original
452
                unlink($tmp_file);
453
                return false;
454
        }
455
        return true;
456
}
457

    
458
/****f* config/write_config
459
 * NAME
460
 *   write_config - Backup and write the firewall configuration.
461
 * DESCRIPTION
462
 *   write_config() handles backing up the current configuration,
463
 *   applying changes, and regenerating the configuration cache.
464
 * INPUTS
465
 *   $desc	- string containing the a description of configuration changes
466
 *   $backup	- boolean: do not back up current configuration if false.
467
 * RESULT
468
 *   null
469
 ******/
470
/* save the system configuration */
471
function write_config($desc="Unknown", $backup = true) {
472
	global $config, $g;
473

    
474
	/* TODO: Not sure what this was added for; commenting out
475
	 *       for now, since it was preventing config saving. */
476
	// $config = parse_config(true, false, false);
477
	
478
	if($g['bootup']) 
479
		log_error("WARNING! Configuration written on bootup.  This can cause stray openvpn and load balancing items in config.xml");
480

    
481
	if($backup)
482
		backup_config();
483

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

    
487
	/* Log the running script so it's not entirely unlogged what changed */
488
	if ($desc == "Unknown")
489
		$desc = "{$_SERVER['SCRIPT_NAME']} made unknown change";
490

    
491
	$config['revision']['description'] = "{$_SESSION['Username']}: " . $desc;
492
	$config['revision']['username'] = $_SESSION["Username"];
493

    
494
	conf_mount_rw();
495
	$lockkey = lock('config', LOCK_EX);
496

    
497
	/* generate configuration XML */
498
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
499

    
500
	/* write new configuration */
501
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
502
		log_error("WARNING: Config contents could not be save. Could not open file!");
503
		unlock($lockkey);
504
		file_notice("config.xml", "Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
505
		return -1;
506
	}
507
	
508
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
509
		cleanup_backupcache(5, true);
510
	} else {
511
		cleanup_backupcache(30, true);
512
	}
513

    
514
	/* re-read configuration */
515
	/* NOTE: We assume that the file can be parsed since we wrote it. */
516
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
517
	if ($config == -1) {
518
		$last_backup = discover_last_backup();
519
		if ($last_backup)
520
			restore_backup("/cf/conf/backup/{$last_backup}");
521
		else
522
			log_error(gettext("Could not restore config.xml."));
523
	} else
524
		generate_config_cache($config);
525

    
526
	unlock($lockkey);
527

    
528
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
529

    
530
	/* tell kernel to sync fs data */
531
	conf_mount_ro();
532

    
533
	/* sync carp entries to other firewalls */
534
	carp_sync_client();
535

    
536
	if(is_dir("/usr/local/pkg/write_config")) {
537
		/* process packager manager custom rules */
538
		run_plugins("/usr/local/pkg/write_config/");
539
	}
540

    
541
	return $config;
542
}
543

    
544
/****f* config/reset_factory_defaults
545
 * NAME
546
 *   reset_factory_defaults - Reset the system to its default configuration.
547
 * RESULT
548
 *   integer	- indicates completion
549
 ******/
550
function reset_factory_defaults($lock = false) {
551
	global $g;
552

    
553
	conf_mount_rw();
554
	if (!$lock)
555
		$lockkey = lock('config', LOCK_EX);
556

    
557
	/* create conf directory, if necessary */
558
	safe_mkdir("{$g['cf_conf_path']}");
559

    
560
	/* clear out /conf */
561
	$dh = opendir($g['conf_path']);
562
	while ($filename = readdir($dh)) {
563
		if (($filename != ".") && ($filename != "..")) {
564
			unlink_if_exists($g['conf_path'] . "/" . $filename);
565
		}
566
	}
567
	closedir($dh);
568

    
569
	/* copy default configuration */
570
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
571

    
572
	/* call the wizard */
573
	touch("/conf/trigger_initial_wizard");
574
	if (!$lock)
575
		unlock($lockkey);
576
	conf_mount_ro();
577

    
578
	return 0;
579
}
580

    
581
function config_restore($conffile) {
582
	global $config, $g;
583

    
584
	if (!file_exists($conffile))
585
		return 1;
586

    
587
	backup_config();
588

    
589
	conf_mount_rw();
590
	
591
	$lockkey = lock('config', LOCK_EX);
592

    
593
	unlink_if_exists("{$g['tmp_path']}/config.cache");
594
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
595

    
596
	unlock($lockkey);
597

    
598
	$config = parse_config(true);
599

    
600
	conf_mount_ro();
601

    
602
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
603

    
604
	return 0;
605
}
606

    
607
function config_install($conffile) {
608
	global $config, $g;
609

    
610
	if (!file_exists($conffile))
611
		return 1;
612

    
613
	if (!config_validate("{$conffile}"))
614
		return 1;
615

    
616
	if($g['booting'] == true)
617
		echo "Installing configuration...\n";
618
	else
619
		log_error("Installing configuration ....");
620

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

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

    
626
	/* unlink cache file if it exists */
627
	if(file_exists("{$g['tmp_path']}/config.cache"))
628
		unlink("{$g['tmp_path']}/config.cache");
629

    
630
	unlock($lockkey);
631
	conf_mount_ro();
632

    
633
    return 0;
634
}
635

    
636
function config_validate($conffile) {
637

    
638
	global $g, $xmlerr;
639

    
640
	$xml_parser = xml_parser_create();
641

    
642
	if (!($fp = fopen($conffile, "r"))) {
643
		$xmlerr = "XML error: unable to open file";
644
		return false;
645
	}
646

    
647
	while ($data = fread($fp, 4096)) {
648
		if (!xml_parse($xml_parser, $data, feof($fp))) {
649
			$xmlerr = sprintf("%s at line %d",
650
						xml_error_string(xml_get_error_code($xml_parser)),
651
						xml_get_current_line_number($xml_parser));
652
			return false;
653
		}
654
	}
655
	xml_parser_free($xml_parser);
656

    
657
	fclose($fp);
658

    
659
	return true;
660
}
661

    
662
function cleanup_backupcache($revisions = 30, $lock = false) {
663
	global $g;
664
	$i = false;
665
	
666
	if (!$lock)
667
		$lockkey = lock('config');
668

    
669
	conf_mount_rw();
670

    
671
	$backups = get_backups();
672
	if ($backups) {
673
		$baktimes = $backups['versions'];
674
		unset($backups['versions']);
675
	} else {
676
		$backups = array();
677
		$baktimes = array();
678
	}
679
	$newbaks = array();
680
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
681
	$tocache = array();
682

    
683
	foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
684
		if(filesize($backup) == 0) {
685
			unlink($backup);
686
			continue;
687
		}
688
		$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
689
		if(!in_array($tocheck, $baktimes)) {
690
			$i = true;
691
			if($g['booting'])
692
				echo ".";
693
			$newxml = parse_xml_config($backup, $g['xml_rootobj']);
694
			if($newxml == "-1") {
695
				log_error("The backup cache file $backup is corrupted.  Unlinking.");
696
				unlink($backup);
697
				log_error("The backup cache file $backup is corrupted.  Unlinking.");
698
				continue;
699
			}
700
			if($newxml['revision']['description'] == "")
701
				$newxml['revision']['description'] = "Unknown";
702
			$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
703
		}
704
	}
705
	foreach($backups as $checkbak) {
706
		if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
707
			$newbaks[] = $checkbak;
708
		} else {
709
			$i = true;
710
			if($g['booting']) print " " . $tocheck . "r";
711
		}
712
	}
713
	foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
714
	if(is_int($revisions) and (count($tocache) > $revisions)) {
715
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
716
		foreach($toslice as $sliced)
717
			$newcache[$sliced] = $tocache[$sliced];
718
		foreach($tocache as $version => $versioninfo) {
719
			if(!in_array($version, array_keys($newcache))) {
720
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
721
				if($g['booting']) print " " . $tocheck . "d";
722
			}
723
		}
724
		$tocache = $newcache;
725
	}
726
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
727
	fwrite($bakout, serialize($tocache));
728
	fclose($bakout);
729
	conf_mount_ro();
730

    
731
	if (!$lock)
732
		unlock($lockkey);
733
}
734

    
735
function get_backups() {
736
	global $g;
737
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
738
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
739
		$bakvers = array_keys($confvers);
740
		$toreturn = array();
741
		sort($bakvers);
742
		// 	$bakvers = array_reverse($bakvers);
743
		foreach(array_reverse($bakvers) as $bakver)
744
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
745
	} else {
746
		return false;
747
	}
748
	$toreturn['versions'] = $bakvers;
749
	return $toreturn;
750
}
751

    
752
function backup_config() {
753
	global $config, $g;
754

    
755
	if($g['platform'] == "cdrom")
756
		return;
757

    
758
	conf_mount_rw();
759

    
760
	/* Create backup directory if needed */
761
	safe_mkdir("{$g['cf_conf_path']}/backup");
762

    
763
    if($config['revision']['time'] == "") {
764
            $baktime = 0;
765
    } else {
766
            $baktime = $config['revision']['time'];
767
    }
768
    if($config['revision']['description'] == "") {
769
            $bakdesc = "Unknown";
770
    } else {
771
            $bakdesc = $config['revision']['description'];
772
    }
773
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
774
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
775
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
776
    } else {
777
            $backupcache = array();
778
    }
779
    $backupcache[$baktime] = array('description' => $bakdesc);
780
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
781
    fwrite($bakout, serialize($backupcache));
782
    fclose($bakout);
783

    
784
	conf_mount_ro();
785

    
786
	return true;
787
}
788

    
789
function set_device_perms() {
790
	$devices = array(
791
		'pf'	=> array(	'user'	=> 'root',
792
					'group'	=> 'proxy',
793
					'mode'	=> 0660),
794
		);
795

    
796
	foreach ($devices as $name => $attr) {
797
		$path = "/dev/$name";
798
		if (file_exists($path)) {
799
			chown($path, $attr['user']);
800
			chgrp($path, $attr['group']);
801
			chmod($path, $attr['mode']);
802
		}
803
	}
804
}
805

    
806
?>
(12-12/54)