Project

General

Profile

Download (28.5 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/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 (!platform_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
				pfSense_fsync("{$g['conf_path']}/config.xml");
82
			} else {
83
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
84
			}
85
		}
86
	}
87
}
88

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

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

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

    
115
	if (platform_booting(true))
116
		echo ".";
117

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

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

    
158
	if (platform_booting(true))
159
		echo ".";
160

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

    
164
	alias_make_table($config);
165

    
166
	return $config;
167
}
168

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

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

    
196
function discover_last_backup() {
197
	$backups = glob('/cf/conf/backup/*.xml');
198
	$last_backup = "";
199
	$last_mtime = 0;
200
	foreach($backups as $backup) {
201
		if(filemtime($backup) > $last_mtime) {
202
			$last_mtime = filemtime($backup);
203
			$last_backup = $backup;
204
		}
205
	}
206

    
207
	return basename($last_backup);
208
}
209

    
210
function restore_backup($file) {
211
	global $g;
212

    
213
	if (file_exists($file)) {
214
		conf_mount_rw();
215
		unlink_if_exists("{$g['tmp_path']}/config.cache");
216
		copy("$file","/cf/conf/config.xml");
217
		pfSense_fsync("/cf/conf/config.xml");
218
		pfSense_fsync($g['conf_path']);
219
		disable_security_checks();
220
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
221
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
222
		conf_mount_ro();
223
	}
224
}
225

    
226
/****f* config/parse_config_bootup
227
 * NAME
228
 *   parse_config_bootup - Bootup-specific configuration checks.
229
 * RESULT
230
 *   null
231
 ******/
232
function parse_config_bootup() {
233
	global $config, $g;
234

    
235
	if (platform_booting())
236
		echo ".";
237

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

    
274
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
275
		$last_backup = discover_last_backup();
276
		if($last_backup) {
277
			log_error(gettext("No config.xml found, attempting last known config restore."));
278
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
279
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
280
		} else {
281
			unlock($lockkey);
282
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
283
		}
284
	}
285
	unlock($lockkey);
286

    
287
	$config = parse_config(true);
288

    
289
	if ((float)$config['version'] > (float)$g['latest_config']) {
290
		echo <<<EOD
291

    
292

    
293
*******************************************************************************
294
* WARNING!                                                                    *
295
* The current configuration has been created with a newer version of {$g['product_name']}  *
296
* than this one! This can lead to serious misbehavior and even security       *
297
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
298
* revert to the default configuration immediately!                            *
299
*******************************************************************************
300

    
301

    
302
EOD;
303
		}
304

    
305
	/* make alias table (for faster lookups) */
306
	alias_make_table($config);
307
}
308

    
309
/****f* config/conf_mount_rw
310
 * NAME
311
 *   conf_mount_rw - Mount filesystems read/write.
312
 * RESULT
313
 *   null
314
 ******/
315
/* mount flash card read/write */
316
function conf_mount_rw() {
317
	global $g, $config;
318

    
319
	/* do not mount on cdrom platform */
320
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
321
		return;
322

    
323
	if ((refcount_reference(1000) > 1) && is_writable("/"))
324
		return;
325

    
326
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
327
	if($status <> 0) {
328
		if (platform_booting())
329
			echo gettext("Disk is dirty.  Running fsck -y") . "\n";
330
		mwexec("/sbin/fsck -y {$g['cf_path']}");
331
		$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
332
	}
333

    
334
	/*    if the platform is soekris or wrap or pfSense, lets mount the
335
	 *    compact flash cards root.
336
         */
337
	$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
338
	/* we could not mount this correctly.  kick off fsck */
339
	if($status <> 0) {
340
		log_error(gettext("File system is dirty.  Launching FSCK for /"));
341
		mwexec("/sbin/fsck -y /");
342
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
343
	}
344
	
345
	mark_subsystem_dirty('mount');
346
}
347

    
348
/****f* config/conf_mount_ro
349
 * NAME
350
 *   conf_mount_ro - Mount filesystems readonly.
351
 * RESULT
352
 *   null
353
 ******/
354
function conf_mount_ro() {
355
	global $g, $config;
356

    
357
	/* Do not trust $g['platform'] since this can be clobbered during factory reset. */
358
	$platform = trim(file_get_contents("/etc/platform"));
359
	/* do not umount on cdrom or pfSense platforms */
360
	if($platform == "cdrom" or $platform == "pfSense")
361
		return;
362

    
363
	if (refcount_unreference(1000) > 0)
364
		return;
365

    
366
	if(isset($config['system']['nanobsd_force_rw']))
367
		return;
368

    
369
	if (platform_booting())
370
		return;
371

    
372
	clear_subsystem_dirty('mount');
373
	/* sync data, then force a remount of /cf */
374
	pfSense_fsync($g['cf_path']);
375
	mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
376
	mwexec("/sbin/mount -u -r -f -o sync,noatime /");
377
}
378

    
379
/****f* config/convert_config
380
 * NAME
381
 *   convert_config - Attempt to update config.xml.
382
 * DESCRIPTION
383
 *   convert_config() reads the current global configuration
384
 *   and attempts to convert it to conform to the latest
385
 *   config.xml version. This allows major formatting changes
386
 *   to be made with a minimum of breakage.
387
 * RESULT
388
 *   null
389
 ******/
390
/* convert configuration, if necessary */
391
function convert_config() {
392
	global $config, $g;
393
	$now = date("H:i:s");
394
	log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
395
	//ini_set("max_execution_time", "900");
396

    
397
	/* special case upgrades */
398
	/* fix every minute crontab bogons entry */
399
	if (is_array($config['cron'])) {
400
		$cron_item_count = count($config['cron']['item']);
401
		for($x=0; $x<$cron_item_count; $x++) {
402
			if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
403
				if($config['cron']['item'][$x]['hour'] == "*" ) {
404
				$config['cron']['item'][$x]['hour'] = "3";
405
					write_config(gettext("Updated bogon update frequency to 3am"));
406
					log_error(gettext("Updated bogon update frequency to 3am"));
407
				}       
408
			}
409
		}
410
	}
411
	if ($config['version'] == $g['latest_config'])
412
		return;		/* already at latest version */
413

    
414
	// Save off config version
415
	$prev_version = $config['version'];
416
	
417
	include_once('auth.inc');
418
	include_once('upgrade_config.inc');
419
	if (file_exists("/etc/inc/upgrade_config_custom.inc"))
420
		include_once("upgrade_config_custom.inc");
421
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
422
	while ($config['version'] < $g['latest_config']) {
423
		$cur = $config['version'] * 10;
424
		$next = $cur + 1;
425
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
426
		if (function_exists($migration_function))
427
			$migration_function();
428
		$migration_function = "{$migration_function}_custom";
429
		if (function_exists($migration_function))
430
			$migration_function();
431
		$config['version'] = sprintf('%.1f', $next / 10);
432
		if (platform_booting())
433
			echo ".";
434
	}
435

    
436
	$now = date("H:i:s");
437
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
438

    
439
	if ($prev_version != $config['version'])
440
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
441
}
442

    
443
/****f* config/safe_write_file
444
 * NAME
445
 *   safe_write_file - Write a file out atomically
446
 * DESCRIPTION
447
 *   safe_write_file() Writes a file out atomically by first writing to a
448
 *   temporary file of the same name but ending with the pid of the current
449
 *   process, them renaming the temporary file over the original.
450
 * INPUTS
451
 *   $filename  - string containing the filename of the file to write
452
 *   $content   - string containing the file content to write to file
453
 *   $force_binary      - boolean denoting whether we should force binary
454
 *   mode writing.
455
 * RESULT
456
 *   boolean - true if successful, false if not
457
 ******/
458
function safe_write_file($file, $content, $force_binary) {
459
	$tmp_file = $file . "." . getmypid();
460
	$write_mode = $force_binary ? "wb" : "w";
461

    
462
	$fd = fopen($tmp_file, $write_mode);
463
	if (!$fd) {
464
		// Unable to open temporary file for writing
465
		return false;
466
        }
467
	if (!fwrite($fd, $content)) {
468
		// Unable to write to temporary file
469
		fclose($fd);
470
		return false;
471
	}
472
	fflush($fd);
473
	fclose($fd);
474

    
475
	if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
476
		// Unable to move temporary file to original
477
		@unlink($tmp_file);
478
		return false;
479
	}
480

    
481
	// Sync file before returning
482
	return pfSense_fsync($file);
483
}
484

    
485
/****f* config/write_config
486
 * NAME
487
 *   write_config - Backup and write the firewall configuration.
488
 * DESCRIPTION
489
 *   write_config() handles backing up the current configuration,
490
 *   applying changes, and regenerating the configuration cache.
491
 * INPUTS
492
 *   $desc	- string containing the a description of configuration changes
493
 *   $backup	- boolean: do not back up current configuration if false.
494
 * RESULT
495
 *   null
496
 ******/
497
/* save the system configuration */
498
function write_config($desc="Unknown", $backup = true) {
499
	global $config, $g;
500

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

    
513
	if (!isset($argc))
514
		session_commit();
515

    
516
	if($backup)
517
		backup_config();
518

    
519
	$config['revision'] = make_config_revision_entry($desc);
520

    
521
	conf_mount_rw();
522
	$lockkey = lock('config', LOCK_EX);
523

    
524
	/* generate configuration XML */
525
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
526

    
527
	/* write new configuration */
528
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
529
		log_error(gettext("WARNING: Config contents could not be saved. Could not open file!"));
530
		unlock($lockkey);
531
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
532
		return -1;
533
	}
534
	
535
	cleanup_backupcache(true);
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 (platform_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
	unlink_if_exists($g['tmp_path'] . "/config.cache");
599

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

    
603
	disable_security_checks();
604

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

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

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

    
620
	backup_config();
621

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

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

    
629
	disable_security_checks();
630

    
631
	unlock($lockkey);
632

    
633
	$config = parse_config(true);
634

    
635
	conf_mount_ro();
636

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

    
639
	return 0;
640
}
641

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

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

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

    
651
	if (platform_booting())
652
		echo gettext("Installing configuration...") . "\n";
653
	else
654
		log_error(gettext("Installing configuration ...."));
655

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

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

    
661
	disable_security_checks();
662

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

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

    
670
    return 0;
671
}
672

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

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

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

    
698
function config_validate($conffile) {
699

    
700
	global $g, $xmlerr;
701

    
702
	$xml_parser = xml_parser_create();
703

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

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

    
719
	fclose($fp);
720

    
721
	return true;
722
}
723

    
724
function cleanup_backupcache($lock = false) {
725
	global $g;
726
	$i = false;
727

    
728
	$revisions = get_config_backup_count();
729

    
730
	if (!$lock)
731
		$lockkey = lock('config');
732

    
733
	conf_mount_rw();
734

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

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

    
801
	if (!$lock)
802
		unlock($lockkey);
803
}
804

    
805
function get_backups() {
806
	global $g;
807
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
808
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
809
		$bakvers = array_keys($confvers);
810
		$toreturn = array();
811
		sort($bakvers);
812
		// 	$bakvers = array_reverse($bakvers);
813
		foreach(array_reverse($bakvers) as $bakver)
814
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
815
	} else {
816
		return false;
817
	}
818
	$toreturn['versions'] = $bakvers;
819
	return $toreturn;
820
}
821

    
822
function backup_config() {
823
	global $config, $g;
824

    
825
	if($g['platform'] == "cdrom")
826
		return;
827

    
828
	conf_mount_rw();
829

    
830
	/* Create backup directory if needed */
831
	safe_mkdir("{$g['cf_conf_path']}/backup");
832
	
833
	if($config['revision']['time'] == "") {
834
		$baktime = 0;
835
	} else {
836
		$baktime = $config['revision']['time'];
837
	}
838
	if($config['revision']['description'] == "") {
839
		$bakdesc = "Unknown";
840
	} else {
841
		$bakdesc = $config['revision']['description'];
842
	}
843

    
844
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
845
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
846
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
847
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
848
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
849
	} else {
850
		$backupcache = array();
851
	}
852
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
853
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
854
	fwrite($bakout, serialize($backupcache));
855
	fclose($bakout);
856
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
857

    
858
	conf_mount_ro();
859

    
860
	return true;
861
}
862

    
863
function set_device_perms() {
864
	$devices = array(
865
		'pf'	=> array(	'user'	=> 'root',
866
					'group'	=> 'proxy',
867
					'mode'	=> 0660),
868
		);
869

    
870
	foreach ($devices as $name => $attr) {
871
		$path = "/dev/$name";
872
		if (file_exists($path)) {
873
			chown($path, $attr['user']);
874
			chgrp($path, $attr['group']);
875
			chmod($path, $attr['mode']);
876
		}
877
	}
878
}
879

    
880
function get_config_user() {
881
	if (empty($_SESSION["Username"])) {
882
		$username = getenv("USER");
883
		if (empty($conuser) || $conuser == "root")
884
			$username = "(system)";
885
	} else
886
		$username = $_SESSION["Username"];
887

    
888
	if (!empty($_SERVER['REMOTE_ADDR']))
889
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
890

    
891
	return $username;
892
}
893

    
894
function make_config_revision_entry($desc = null, $override_user = null) {
895
	if (empty($override_user))
896
		$username = get_config_user();
897
	else
898
		$username = $override_user;
899

    
900
	$revision = array();
901

    
902
	if (time() > mktime(0, 0, 0, 9, 1, 2004))       /* make sure the clock settings are plausible */
903
		$revision['time'] = time();
904

    
905
	/* Log the running script so it's not entirely unlogged what changed */
906
	if ($desc == "Unknown")
907
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
908
	if (!empty($desc))
909
		$revision['description'] = "{$username}: " . $desc;
910
	$revision['username'] = $username;
911
	return $revision;
912
}
913

    
914
function get_config_backup_count() {
915
	global $config, $g;
916
	if (isset($config['system']['backupcount']) && is_numeric($config['system']['backupcount']) && ($config['system']['backupcount'] >= 0)) {
917
		return intval($config['system']['backupcount']);
918
	} elseif ($g['platform'] == "nanobsd") {
919
		return 5;
920
	} else {
921
		return 30;
922
	}
923
}
924

    
925
function pfSense_clear_globals() {
926
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
927

    
928
	$error = error_get_last();
929
	
930
	if ( $error !== NULL) {
931
		if ( $error['type'] != E_NOTICE ) {
932
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
933
			// XXX: comment out for now, should re-enable post-2.2
934
			//print($errorstr);
935
			//log_error($errorstr);
936
		}
937
	}
938

    
939
	if (isset($FilterIfList))
940
		unset($FilterIfList);
941

    
942
	if (isset($GatewaysList))
943
		unset($GatewaysList);
944

    
945
	/* Used for the hostname dns resolver */
946
	if (isset($filterdns))
947
		unset($filterdns);
948

    
949
	/* Used for aliases and interface macros */
950
	if (isset($aliases))
951
		unset($aliases);
952
	if (isset($aliastable))
953
		unset($aliastable);
954

    
955
	unset($config);
956
}
957

    
958
register_shutdown_function('pfSense_clear_globals');
959

    
960
?>
(12-12/68)