Project

General

Profile

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

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

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

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

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

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

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

    
41

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

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

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

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

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

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

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

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

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

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

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

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

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

    
163
	alias_make_table($config);
164

    
165
	return $config;
166
}
167

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

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

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

    
199
        return $last_backup;
200
}
201

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

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

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

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

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

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

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

    
280

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

    
289

    
290
EOD;
291
		}
292

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
470
	return true;
471
}
472

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

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

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

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

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

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

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

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

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

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

    
559
	unlock($lockkey);
560

    
561
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
562

    
563
	/* tell kernel to sync fs data */
564
	conf_mount_ro();
565

    
566
	/* sync carp entries to other firewalls */
567
	carp_sync_client();
568

    
569
	if(is_dir("/usr/local/pkg/write_config")) {
570
		/* process packager manager custom rules */
571
		run_plugins("/usr/local/pkg/write_config/");
572
	}
573

    
574
	return $config;
575
}
576

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

    
586
	conf_mount_rw();
587
	if (!$lock)
588
		$lockkey = lock('config', LOCK_EX);
589

    
590
	/* create conf directory, if necessary */
591
	safe_mkdir("{$g['cf_conf_path']}");
592

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

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

    
605
	disable_security_checks();
606

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

    
616
function config_restore($conffile) {
617
	global $config, $g;
618

    
619
	if (!file_exists($conffile))
620
		return 1;
621

    
622
	backup_config();
623

    
624
	conf_mount_rw();
625
	
626
	$lockkey = lock('config', LOCK_EX);
627

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

    
631
	disable_security_checks();
632

    
633
	unlock($lockkey);
634

    
635
	$config = parse_config(true);
636

    
637
	conf_mount_ro();
638

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

    
641
	return 0;
642
}
643

    
644
function config_install($conffile) {
645
	global $config, $g;
646

    
647
	if (!file_exists($conffile))
648
		return 1;
649

    
650
	if (!config_validate("{$conffile}"))
651
		return 1;
652

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

    
658
	conf_mount_rw();
659
	$lockkey = lock('config', LOCK_EX);
660

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

    
663
	disable_security_checks();
664

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

    
669
	unlock($lockkey);
670
	conf_mount_ro();
671

    
672
    return 0;
673
}
674

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

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

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

    
700
function config_validate($conffile) {
701

    
702
	global $g, $xmlerr;
703

    
704
	$xml_parser = xml_parser_create();
705

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

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

    
721
	fclose($fp);
722

    
723
	return true;
724
}
725

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

    
797
	if (!$lock)
798
		unlock($lockkey);
799
}
800

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

    
818
function backup_config() {
819
	global $config, $g;
820

    
821
	if($g['platform'] == "cdrom")
822
		return;
823

    
824
	conf_mount_rw();
825

    
826
	/* Create backup directory if needed */
827
	safe_mkdir("{$g['cf_conf_path']}/backup");
828

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

    
840
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
841

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

    
853
	conf_mount_ro();
854

    
855
	return true;
856
}
857

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

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

    
875
function get_config_user() {
876
	if (empty($_SESSION["Username"])) {
877
		if (empty($_ENV['USER']) || $_ENV['USER'] == "root")
878
			$username = "(system)";
879
		else
880
			$username = $_ENV['USER'];
881
	} else
882
		$username = $_SESSION["Username"];
883

    
884
	if (!empty($_SERVER['REMOTE_ADDR']))
885
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
886

    
887
	return $username;
888
}
889

    
890
function make_config_revision_entry($desc = null, $override_user = null) {
891
	if (empty($override_user))
892
		$username = get_config_user();
893
	else
894
		$username = $override_user;
895

    
896
	$revision = array();
897

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

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

    
910
?>
(13-13/66)