Project

General

Profile

Download (23.9 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
			}
130
			unlock($lockkey);
131
			$config = parse_config(true);
132
			$lockkey = lock('config');
133
		}
134
	} else {
135
		if(!file_exists($g['conf_path'] . "/config.xml")) {
136
			if($g['booting']) echo ".";
137
			log_error("No config.xml found, attempting last known config restore.");
138
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
139
			$last_backup = discover_last_backup();
140
			if ($last_backup)
141
				restore_backup("/cf/conf/backup/{$last_backup}");
142
			else
143
				log_error("Could not restore config.xml.");
144
		}
145
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
146
		if($config == "-1") {
147
			$last_backup = discover_last_backup();
148
			if ($last_backup)
149
				restore_backup("/cf/conf/backup/{$last_backup}");
150
			else
151
				log_error(gettext("Could not restore config.xml."));
152
		}
153
		generate_config_cache($config);
154
	}
155
	if($g['booting']) echo ".";
156
	alias_make_table($config);
157
	$config_parsed = true;
158
	unlock($lockkey);
159

    
160
	return $config;
161
}
162

    
163
/****f* config/generate_config_cache
164
 * NAME
165
 *   generate_config_cache - Write serialized configuration to cache.
166
 * INPUTS
167
 *   $config	- array containing current firewall configuration
168
 * RESULT
169
 *   boolean	- true on completion
170
 ******/
171
function generate_config_cache($config) {
172
	global $g, $config_extra;
173

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

    
187
function discover_last_backup() {
188
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
189
	$last_backup = "";
190
        foreach($backups as $backup)
191
        	if($backup)
192
	        	$last_backup = $backup;
193

    
194
        return $last_backup;
195
}
196

    
197
function restore_backup($file) {
198
	global $g;
199

    
200
	if (file_exists($file)) {
201
		conf_mount_rw();
202
		unlink_if_exists("{$g['tmp_path']}/config.cache");
203
		copy("$file","/cf/conf/config.xml");
204
		log_error("{$g['product_name']} is restoring the configuration $file");
205
		file_notice("config.xml", "{$g['product_name']} is restoring the configuration $file", "pfSenseConfigurator", "");
206
		conf_mount_ro();
207
	}
208
}
209

    
210
/****f* config/parse_config_bootup
211
 * NAME
212
 *   parse_config_bootup - Bootup-specific configuration checks.
213
 * RESULT
214
 *   null
215
 ******/
216
function parse_config_bootup() {
217
	global $config, $g, $noparseconfig;
218

    
219
	if($g['booting']) echo ".";
220

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

    
272
	if ((float)$config['version'] > (float)$g['latest_config']) {
273
		echo <<<EOD
274

    
275

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

    
284

    
285
EOD;
286
		}
287

    
288
	/* make alias table (for faster lookups) */
289
	alias_make_table($config);
290
}
291

    
292
/****f* config/conf_mount_rw
293
 * NAME
294
 *   conf_mount_rw - Mount filesystems read/write.
295
 * RESULT
296
 *   null
297
 ******/
298
/* mount flash card read/write */
299
function conf_mount_rw() {
300
	global $g;
301

    
302
	/* do not mount on cdrom platform */
303
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
304
		return;
305

    
306
	if (refcount_reference(1000) > 1)
307
		return;
308

    
309
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
310
	if($status <> 0) {
311
		if($g['booting'])
312
			echo "Disk is dirty.  Running fsck -y\n";
313
		mwexec("/sbin/fsck -y {$g['cf_path']}");
314
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
315
	}
316

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

    
331
/****f* config/conf_mount_ro
332
 * NAME
333
 *   conf_mount_ro - Mount filesystems readonly.
334
 * RESULT
335
 *   null
336
 ******/
337
function conf_mount_ro() {
338
	global $g;
339

    
340
	/* do not umount on cdrom or pfSense platforms */
341
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
342
		return;
343

    
344
	if (refcount_unreference(1000) > 0)
345
		return;
346

    
347
	clear_subsystem_dirty('mount');
348
	/* sync data, then force a remount of /cf */
349
	mwexec("/bin/sync; /bin/sync");
350
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
351
	mwexec("/sbin/mount -u -r -f /");
352
}
353

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

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

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

    
403
	$now = date("H:i:s");
404
	log_error("Ended Configuration upgrade at $now");
405

    
406
	if ($prev_version != $config['version'])
407
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
408

    
409
	if($g['booting'])
410
		echo "Loading new configuration...";
411
}
412

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

    
432
        $fd = fopen($tmp_file, $write_mode);
433
        if (!$fd) {
434
                // Unable to open temporary file for writing
435
                return false;
436
        }
437
        if (!fwrite($fd, $content)) {
438
                // Unable to write to temporary file
439
                fclose($fd);
440
                return false;
441
        }
442
        fclose($fd);
443

    
444
        if (!rename($tmp_file, $file)) {
445
                // Unable to move temporary file to original
446
                unlink($tmp_file);
447
                return false;
448
        }
449
        return true;
450
}
451

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

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

    
475
	if($backup)
476
		backup_config();
477

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

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

    
485
	$config['revision']['description'] = "{$_SESSION['Username']}: " . $desc;
486
	$config['revision']['username'] = $_SESSION["Username"];
487

    
488
	conf_mount_rw();
489
	$lockkey = lock('config', LOCK_EX);
490

    
491
	/* generate configuration XML */
492
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
493

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

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

    
520
	unlock($lockkey);
521

    
522
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
523

    
524
	/* tell kernel to sync fs data */
525
	conf_mount_ro();
526

    
527
	/* sync carp entries to other firewalls */
528
	carp_sync_client();
529

    
530
	if(is_dir("/usr/local/pkg/write_config")) {
531
		/* process packager manager custom rules */
532
		run_plugins("/usr/local/pkg/write_config/");
533
	}
534

    
535
	return $config;
536
}
537

    
538
/****f* config/reset_factory_defaults
539
 * NAME
540
 *   reset_factory_defaults - Reset the system to its default configuration.
541
 * RESULT
542
 *   integer	- indicates completion
543
 ******/
544
function reset_factory_defaults($lock = false) {
545
	global $g;
546

    
547
	conf_mount_rw();
548
	if (!$lock)
549
		$lockkey = lock('config', LOCK_EX);
550

    
551
	/* create conf directory, if necessary */
552
	safe_mkdir("{$g['cf_conf_path']}");
553

    
554
	/* clear out /conf */
555
	$dh = opendir($g['conf_path']);
556
	while ($filename = readdir($dh)) {
557
		if (($filename != ".") && ($filename != "..")) {
558
			unlink_if_exists($g['conf_path'] . "/" . $filename);
559
		}
560
	}
561
	closedir($dh);
562

    
563
	/* copy default configuration */
564
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
565

    
566
	/* call the wizard */
567
	touch("/conf/trigger_initial_wizard");
568
	if (!$lock)
569
		unlock($lockkey);
570
	conf_mount_ro();
571

    
572
	return 0;
573
}
574

    
575
function config_restore($conffile) {
576
	global $config, $g;
577

    
578
	if (!file_exists($conffile))
579
		return 1;
580

    
581
	backup_config();
582

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

    
587
	unlink_if_exists("{$g['tmp_path']}/config.cache");
588
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
589

    
590
	unlock($lockkey);
591

    
592
	$config = parse_config(true);
593

    
594
	conf_mount_ro();
595

    
596
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
597

    
598
	return 0;
599
}
600

    
601
function config_install($conffile) {
602
	global $config, $g;
603

    
604
	if (!file_exists($conffile))
605
		return 1;
606

    
607
	if (!config_validate("{$conffile}"))
608
		return 1;
609

    
610
	if($g['booting'] == true)
611
		echo "Installing configuration...\n";
612
	else
613
		log_error("Installing configuration ....");
614

    
615
	conf_mount_rw();
616
	$lockkey = lock('config', LOCK_EX);
617

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

    
620
	/* unlink cache file if it exists */
621
	if(file_exists("{$g['tmp_path']}/config.cache"))
622
		unlink("{$g['tmp_path']}/config.cache");
623

    
624
	unlock($lockkey);
625
	conf_mount_ro();
626

    
627
    return 0;
628
}
629

    
630
function config_validate($conffile) {
631

    
632
	global $g, $xmlerr;
633

    
634
	$xml_parser = xml_parser_create();
635

    
636
	if (!($fp = fopen($conffile, "r"))) {
637
		$xmlerr = "XML error: unable to open file";
638
		return false;
639
	}
640

    
641
	while ($data = fread($fp, 4096)) {
642
		if (!xml_parse($xml_parser, $data, feof($fp))) {
643
			$xmlerr = sprintf("%s at line %d",
644
						xml_error_string(xml_get_error_code($xml_parser)),
645
						xml_get_current_line_number($xml_parser));
646
			return false;
647
		}
648
	}
649
	xml_parser_free($xml_parser);
650

    
651
	fclose($fp);
652

    
653
	return true;
654
}
655

    
656
function cleanup_backupcache($revisions = 30, $lock = false) {
657
	global $g;
658
	$i = false;
659
	
660
	if (!$lock)
661
		$lockkey = lock('config');
662

    
663
	conf_mount_rw();
664

    
665
	$backups = get_backups();
666
	if ($backups) {
667
		$baktimes = $backups['versions'];
668
		unset($backups['versions']);
669
	} else {
670
		$backups = array();
671
		$baktimes = array();
672
	}
673
	$newbaks = array();
674
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
675
	$tocache = array();
676

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

    
725
	if($g['booting'] && $i)
726
		print "done.\n";
727
	if (!$lock)
728
		unlock($lockkey);
729
}
730

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

    
748
function backup_config() {
749
	global $config, $g;
750

    
751
	if($g['platform'] == "cdrom")
752
		return;
753

    
754
	conf_mount_rw();
755

    
756
	/* Create backup directory if needed */
757
	safe_mkdir("{$g['cf_conf_path']}/backup");
758

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

    
780
	conf_mount_ro();
781

    
782
	return true;
783
}
784

    
785
function set_device_perms() {
786
	$devices = array(
787
		'pf'	=> array(	'user'	=> 'root',
788
					'group'	=> 'proxy',
789
					'mode'	=> 0660),
790
		);
791

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

    
802
?>
(11-11/51)