Project

General

Profile

Download (31.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * config.lib.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2009 Erik Kristensen
8
 * All rights reserved.
9
 *
10
 * originally part of m0n0wall (http://m0n0.ch/wall)
11
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
12
 * All rights reserved.
13
 *
14
 * Redistribution and use in source and binary forms, with or without
15
 * modification, are permitted provided that the following conditions are met:
16
 *
17
 * 1. Redistributions of source code must retain the above copyright notice,
18
 *    this list of conditions and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright
21
 *    notice, this list of conditions and the following disclaimer in
22
 *    the documentation and/or other materials provided with the
23
 *    distribution.
24
 *
25
 * 3. All advertising materials mentioning features or use of this software
26
 *    must display the following acknowledgment:
27
 *    "This product includes software developed by the pfSense Project
28
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
29
 *
30
 * 4. The names "pfSense" and "pfSense Project" must not be used to
31
 *    endorse or promote products derived from this software without
32
 *    prior written permission. For written permission, please contact
33
 *    coreteam@pfsense.org.
34
 *
35
 * 5. Products derived from this software may not be called "pfSense"
36
 *    nor may "pfSense" appear in their names without prior written
37
 *    permission of the Electric Sheep Fencing, LLC.
38
 *
39
 * 6. Redistributions of any form whatsoever must retain the following
40
 *    acknowledgment:
41
 *
42
 * "This product includes software developed by the pfSense Project
43
 * for use in the pfSense software distribution (http://www.pfsense.org/).
44
 *
45
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
46
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
49
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
54
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
56
 * OF THE POSSIBILITY OF SUCH DAMAGE.
57
 */
58

    
59
/****f* config/encrypted_configxml
60
 * NAME
61
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
62
 * INPUTS
63
 *   None
64
 * RESULT
65
 *   $config 	- rewrites config.xml without encryption
66
 ******/
67
function encrypted_configxml() {
68
	global $g, $config;
69

    
70
	if (!file_exists($g['conf_path'] . "/config.xml")) {
71
		return;
72
	}
73

    
74
	if (!platform_booting()) {
75
		return;
76
	}
77

    
78
	$configtxt = file_get_contents($g['conf_path'] . "/config.xml");
79
	if (tagfile_deformat($configtxt, $configtxt, "config.xml")) {
80
		$fp = fopen('php://stdin', 'r');
81
		$data = "";
82
		echo "\n\n*** Encrypted config.xml detected ***\n";
83
		while ($data == "") {
84
			echo "\nEnter the password to decrypt config.xml: ";
85
			$decrypt_password = chop(fgets($fp));
86
			$data = decrypt_data($configtxt, $decrypt_password);
87
			if (!strstr($data, "<pfsense>")) {
88
				$data = "";
89
			}
90
			if ($data) {
91
				$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
92
				fwrite($fd, $data);
93
				fclose($fd);
94
				exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
95
				echo "\n" . gettext("Config.xml unlocked.") . "\n";
96
				fclose($fp);
97
				pfSense_fsync("{$g['conf_path']}/config.xml");
98
			} else {
99
				echo "\n" . gettext("Invalid password entered.  Please try again.") . "\n";
100
			}
101
		}
102
	}
103
}
104

    
105
/****f* config/parse_config
106
 * NAME
107
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
108
 * INPUTS
109
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
110
 * RESULT
111
 *   $config      - array containing all configuration variables
112
 ******/
113
function parse_config($parse = false) {
114
	global $g, $config_parsed, $config_extra;
115

    
116
	$lockkey = lock('config');
117
	$config_parsed = false;
118

    
119
	if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
120
		$last_backup = discover_last_backup();
121
		if ($last_backup) {
122
			log_error(gettext("No config.xml found, attempting last known config restore."));
123
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
124
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
125
		} else {
126
			unlock($lockkey);
127
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
128
		}
129
	}
130

    
131
	if (platform_booting(true)) {
132
		echo ".";
133
	}
134

    
135
	// Check for encrypted config.xml
136
	encrypted_configxml();
137

    
138
	if (!$parse) {
139
		if (file_exists($g['tmp_path'] . '/config.cache')) {
140
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
141
			if (!is_array($config)) {
142
				$parse = true;
143
			}
144
		} else {
145
			$parse = true;
146
		}
147
	}
148
	if ($parse == true) {
149
		if (!file_exists($g['conf_path'] . "/config.xml")) {
150
			if (platform_booting(true)) {
151
				echo ".";
152
			}
153
			log_error("No config.xml found, attempting last known config restore.");
154
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
155
			$last_backup = discover_last_backup();
156
			if ($last_backup) {
157
				restore_backup("/cf/conf/backup/{$last_backup}");
158
			} else {
159
				log_error(gettext("Could not restore config.xml."));
160
				unlock($lockkey);
161
				die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
162
			}
163
		}
164
		$config = parse_xml_config($g['conf_path'] . '/config.xml', array($g['xml_rootobj'], 'pfsense'));
165
		if ($config == -1) {
166
			$last_backup = discover_last_backup();
167
			if ($last_backup) {
168
				restore_backup("/cf/conf/backup/{$last_backup}");
169
			} else {
170
				log_error(gettext("Could not restore config.xml."));
171
				unlock($lockkey);
172
				die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
173
			}
174
		}
175
		generate_config_cache($config);
176
	}
177

    
178
	if (platform_booting(true)) {
179
		echo ".";
180
	}
181

    
182
	$config_parsed = true;
183
	unlock($lockkey);
184

    
185
	alias_make_table($config);
186

    
187
	return $config;
188
}
189

    
190
/****f* config/generate_config_cache
191
 * NAME
192
 *   generate_config_cache - Write serialized configuration to cache.
193
 * INPUTS
194
 *   $config	- array containing current firewall configuration
195
 * RESULT
196
 *   boolean	- true on completion
197
 ******/
198
function generate_config_cache($config) {
199
	global $g, $config_extra;
200

    
201
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
202
	fwrite($configcache, serialize($config));
203
	fclose($configcache);
204
	pfSense_fsync("{$g['tmp_path']}/config.cache");
205

    
206
	unset($configcache);
207
	/* Used for config.extra.xml */
208
	if (file_exists($g['tmp_path'] . '/config.extra.cache') && $config_extra) {
209
		$configcacheextra = fopen($g['tmp_path'] . '/config.extra.cache', "w");
210
		fwrite($configcacheextra, serialize($config_extra));
211
		fclose($configcacheextra);
212
		pfSense_fsync("{$g['tmp_path']}/config.extra.cache");
213
		unset($configcacheextra);
214
	}
215
}
216

    
217
function discover_last_backup() {
218
	$backups = glob('/cf/conf/backup/*.xml');
219
	$last_backup = "";
220
	$last_mtime = 0;
221
	foreach ($backups as $backup) {
222
		if (filemtime($backup) > $last_mtime) {
223
			$last_mtime = filemtime($backup);
224
			$last_backup = $backup;
225
		}
226
	}
227

    
228
	return basename($last_backup);
229
}
230

    
231
function restore_backup($file) {
232
	global $g;
233

    
234
	if (file_exists($file)) {
235
		conf_mount_rw();
236
		unlink_if_exists("{$g['tmp_path']}/config.cache");
237
		copy("$file", "/cf/conf/config.xml");
238
		pfSense_fsync("/cf/conf/config.xml");
239
		pfSense_fsync($g['conf_path']);
240
		disable_security_checks();
241
		log_error(sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file));
242
		file_notice("config.xml", sprintf(gettext('%1$s is restoring the configuration %2$s'), $g['product_name'], $file), "pfSenseConfigurator", "");
243
		conf_mount_ro();
244
	}
245
}
246

    
247
/****f* config/parse_config_bootup
248
 * NAME
249
 *   parse_config_bootup - Bootup-specific configuration checks.
250
 * RESULT
251
 *   null
252
 ******/
253
function parse_config_bootup() {
254
	global $config, $g;
255

    
256
	if (platform_booting()) {
257
		echo ".";
258
	}
259

    
260
	$lockkey = lock('config');
261
	if (!file_exists("{$g['conf_path']}/config.xml")) {
262
		if (platform_booting()) {
263
			if (strstr($g['platform'], "cdrom")) {
264
				/* try copying the default config. to the floppy */
265
				echo gettext("Resetting factory defaults...") . "\n";
266
				reset_factory_defaults(true, false);
267
				if (!file_exists("{$g['conf_path']}/config.xml")) {
268
					echo gettext("No XML configuration file found - using factory defaults.\n" .
269
								 "Make sure that the configuration floppy disk with the conf/config.xml\n" .
270
								 "file is inserted. If it isn't, the configuration changes will be lost\n" .
271
								 "on reboot.\n");
272
				}
273
			} else {
274
				$last_backup = discover_last_backup();
275
				if ($last_backup) {
276
					log_error("No config.xml found, attempting last known config restore.");
277
					file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
278
					restore_backup("/cf/conf/backup/{$last_backup}");
279
				}
280
				if (!file_exists("{$g['conf_path']}/config.xml")) {
281
					echo sprintf(gettext("XML configuration file not found.  %s cannot continue booting."), $g['product_name']) . "\n";
282
					unlock($lockkey);
283
					mwexec("/sbin/halt");
284
					exit;
285
				}
286
				log_error("Last known config found and restored.  Please double check the configuration file for accuracy.");
287
				file_notice("config.xml", gettext("Last known config found and restored.  Please double check the configuration file for accuracy."), "pfSenseConfigurator", "");
288
			}
289
		} else {
290
			unlock($lockkey);
291
			log_error(gettext("Could not find a usable configuration file! Exiting...."));
292
			exit(0);
293
		}
294
	}
295

    
296
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
297
		$last_backup = discover_last_backup();
298
		if ($last_backup) {
299
			log_error(gettext("No config.xml found, attempting last known config restore."));
300
			file_notice("config.xml", gettext("No config.xml found, attempting last known config restore."), "pfSenseConfigurator", "");
301
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
302
		} else {
303
			unlock($lockkey);
304
			die(gettext("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup."));
305
		}
306
	}
307
	unlock($lockkey);
308

    
309
	$config = parse_config(true);
310

    
311
	if ((float)$config['version'] > (float)$g['latest_config']) {
312
		echo <<<EOD
313

    
314

    
315
*******************************************************************************
316
* WARNING!                                                                    *
317
* The current configuration has been created with a newer version of {$g['product_name']}  *
318
* than this one! This can lead to serious misbehavior and even security       *
319
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
320
* revert to the default configuration immediately!                            *
321
*******************************************************************************
322

    
323

    
324
EOD;
325
		}
326

    
327
	/* make alias table (for faster lookups) */
328
	alias_make_table($config);
329
}
330

    
331
/****f* config/conf_mount_rw
332
 * NAME
333
 *   conf_mount_rw - Mount filesystems read/write.
334
 * RESULT
335
 *   null
336
 ******/
337
/* mount flash card read/write */
338
function conf_mount_rw() {
339
	global $g, $config;
340

    
341
	/* do not mount on cdrom platform */
342
	if ($g['platform'] == "cdrom" or $g['platform'] == $g['product_name']) {
343
		return;
344
	}
345

    
346
	if ((refcount_reference(1000) > 1) && is_writable("/")) {
347
		return;
348
	}
349

    
350
	$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
351
	if ($status <> 0) {
352
		if (platform_booting()) {
353
			echo gettext("/cf Filesystem is dirty.") . "\n";
354
		}
355
		$status = mwexec("/sbin/mount -u -w -o sync,noatime {$g['cf_path']}");
356
	}
357

    
358
	/*    if the platform is soekris or wrap or $product, lets mount the
359
	 *    compact flash cards root.
360
	*/
361
	$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
362
	/* we could not mount this correctly. */
363
	if ($status <> 0) {
364
		log_error(gettext("/ File system is dirty."));
365
		$status = mwexec("/sbin/mount -u -w -o sync,noatime /");
366
	}
367

    
368
	mark_subsystem_dirty('mount');
369
}
370

    
371
/****f* config/conf_mount_ro
372
 * NAME
373
 *   conf_mount_ro - Mount filesystems readonly.
374
 * RESULT
375
 *   null
376
 ******/
377
function conf_mount_ro() {
378
	global $g, $config;
379

    
380
	// do nothing here. redmine #6184
381
	return;
382

    
383
	/* Do not trust $g['platform'] since this can be clobbered during factory reset. */
384
	$platform = trim(file_get_contents("/etc/platform"));
385
	/* do not umount on cdrom or pfSense platforms */
386
	if ($platform == "cdrom" or $platform == $g['product_name']) {
387
		return;
388
	}
389

    
390
	if (refcount_unreference(1000) > 0) {
391
		return;
392
	}
393

    
394
	if (isset($config['system']['nanobsd_force_rw'])) {
395
		return;
396
	}
397

    
398
	if (platform_booting()) {
399
		return;
400
	}
401

    
402
	clear_subsystem_dirty('mount');
403
	/* sync data, then force a remount of /cf */
404
	pfSense_fsync($g['cf_path']);
405
	mwexec("/sbin/mount -u -r -f -o sync,noatime {$g['cf_path']}");
406
	mwexec("/sbin/mount -u -r -f -o sync,noatime /");
407
}
408

    
409
/****f* config/convert_config
410
 * NAME
411
 *   convert_config - Attempt to update config.xml.
412
 * DESCRIPTION
413
 *   convert_config() reads the current global configuration
414
 *   and attempts to convert it to conform to the latest
415
 *   config.xml version. This allows major formatting changes
416
 *   to be made with a minimum of breakage.
417
 * RESULT
418
 *   null
419
 ******/
420
/* convert configuration, if necessary */
421
function convert_config() {
422
	global $config, $g;
423
	$now = date("H:i:s");
424
	log_error(sprintf(gettext("Start Configuration upgrade at %s, set execution timeout to 15 minutes"), $now));
425
	//ini_set("max_execution_time", "900");
426

    
427
	/* special case upgrades */
428
	/* fix every minute crontab bogons entry */
429
	if (is_array($config['cron'])) {
430
		$cron_item_count = count($config['cron']['item']);
431
		for ($x = 0; $x < $cron_item_count; $x++) {
432
			if (stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
433
				if ($config['cron']['item'][$x]['hour'] == "*") {
434
					$config['cron']['item'][$x]['hour'] = "3";
435
					write_config(gettext("Updated bogon update frequency to 3am"));
436
					log_error(gettext("Updated bogon update frequency to 3am"));
437
				}
438
			}
439
		}
440
	}
441
	if ($config['version'] == $g['latest_config']) {
442
		return;		/* already at latest version */
443
	}
444

    
445
	// Save off config version
446
	$prev_version = $config['version'];
447

    
448
	include_once('auth.inc');
449
	include_once('upgrade_config.inc');
450
	if (file_exists("/etc/inc/upgrade_config_custom.inc")) {
451
		include_once("upgrade_config_custom.inc");
452
	}
453
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
454
	while ($config['version'] < $g['latest_config']) {
455
		$cur = $config['version'] * 10;
456
		$next = $cur + 1;
457
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
458
		if (function_exists($migration_function)) {
459
			$migration_function();
460
		}
461
		$migration_function = "{$migration_function}_custom";
462
		if (function_exists($migration_function)) {
463
			$migration_function();
464
		}
465
		$config['version'] = sprintf('%.1f', $next / 10);
466
		if (platform_booting()) {
467
			echo ".";
468
		}
469
	}
470

    
471
	$now = date("H:i:s");
472
	log_error(sprintf(gettext("Ended Configuration upgrade at %s"), $now));
473

    
474
	if ($prev_version != $config['version']) {
475
		write_config(sprintf(gettext('Upgraded config version level from %1$s to %2$s'), $prev_version, $config['version']));
476
	}
477
}
478

    
479
/****f* config/safe_write_file
480
 * NAME
481
 *   safe_write_file - Write a file out atomically
482
 * DESCRIPTION
483
 *   safe_write_file() Writes a file out atomically by first writing to a
484
 *   temporary file of the same name but ending with the pid of the current
485
 *   process, them renaming the temporary file over the original.
486
 * INPUTS
487
 *   $filename  - string containing the filename of the file to write
488
 *   $content   - string or array containing the file content to write to file
489
 *   $force_binary      - boolean denoting whether we should force binary
490
 *   mode writing.
491
 * RESULT
492
 *   boolean - true if successful, false if not
493
 ******/
494
function safe_write_file($file, $content, $force_binary = false) {
495
	$tmp_file = $file . "." . getmypid();
496
	$write_mode = $force_binary ? "wb" : "w";
497

    
498
	$fd = fopen($tmp_file, $write_mode);
499
	if (!$fd) {
500
		// Unable to open temporary file for writing
501
		return false;
502
	}
503
	if (is_array($content)) {
504
		foreach ($content as $line) {
505
			if (!fwrite($fd, $line . "\n")) {
506
				// Unable to write to temporary file
507
				fclose($fd);
508
				return false;
509
			}
510
		}
511
	} elseif (!fwrite($fd, $content)) {
512
		// Unable to write to temporary file
513
		fclose($fd);
514
		return false;
515
	}
516
	fflush($fd);
517
	fclose($fd);
518

    
519
	if (!pfSense_fsync($tmp_file) || !rename($tmp_file, $file)) {
520
		// Unable to move temporary file to original
521
		@unlink($tmp_file);
522
		return false;
523
	}
524

    
525
	// Sync file before returning
526
	return pfSense_fsync($file);
527
}
528

    
529
/****f* config/write_config
530
 * NAME
531
 *   write_config - Backup and write the firewall configuration.
532
 * DESCRIPTION
533
 *   write_config() handles backing up the current configuration,
534
 *   applying changes, and regenerating the configuration cache.
535
 * INPUTS
536
 *   $desc	- string containing the a description of configuration changes
537
 *   $backup	- boolean: do not back up current configuration if false.
538
 *   $write_config_only	- boolean: do not sync or reload anything; just save the configuration if true.
539
 * RESULT
540
 *   null
541
 ******/
542
/* save the system configuration */
543
function write_config($desc="Unknown", $backup = true, $write_config_only = false) {
544
	global $config, $g;
545

    
546
	if (!empty($_SERVER['REMOTE_ADDR'])) {
547
		if (!session_id()) {
548
			@session_start();
549
		}
550
		if (!empty($_SESSION['Username']) && ($_SESSION['Username'] != "admin")) {
551
			$user = getUserEntry($_SESSION['Username']);
552
			if (is_array($user) && userHasPrivilege($user, "user-config-readonly")) {
553
				session_commit();
554
				return false;
555
			}
556
		}
557
	}
558

    
559
	if (!isset($argc)) {
560
		session_commit();
561
	}
562

    
563
	if (isset($config['reset_factory_defaults'])) {
564
		/*
565
		   We have put a default config.xml on disk and are about to reboot
566
		   or reload it. Do not let any system or package code try to save
567
		   state to config because that would overwrite the default config
568
		   with the running config.
569
		*/
570
		return false;
571
	}
572

    
573
	if ($backup) {
574
		backup_config();
575
	}
576

    
577
	$config['revision'] = make_config_revision_entry($desc);
578

    
579
	conf_mount_rw();
580
	$lockkey = lock('config', LOCK_EX);
581

    
582
	/* generate configuration XML */
583
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
584

    
585
	/* write new configuration */
586
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig)) {
587
		log_error(gettext("WARNING: Config contents could not be saved. Could not open file!"));
588
		unlock($lockkey);
589
		file_notice("config.xml", sprintf(gettext("Unable to open %s/config.xml for writing in write_config()%s"), $g['cf_conf_path'], "\n"));
590
		return -1;
591
	}
592

    
593
	cleanup_backupcache(true);
594

    
595
	/* re-read configuration */
596
	/* NOTE: We assume that the file can be parsed since we wrote it. */
597
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
598
	if ($config == -1) {
599
		copy("{$g['conf_path']}/config.xml", "{$g['conf_path']}/config.xml.bad");
600
		$last_backup = discover_last_backup();
601
		if ($last_backup) {
602
			restore_backup("/cf/conf/backup/{$last_backup}");
603
			$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
604
			if (platform_booting()) {
605
				echo "\n\n ************** WARNING **************";
606
				echo "\n\n Configuration could not be validated. A previous configuration was restored. \n";
607
				echo "\n The failed configuration file has been saved as {$g['conf_path']}/config.xml.bad \n\n";
608
			}
609
		} else {
610
			log_error(gettext("Could not restore config.xml."));
611
		}
612
	} else {
613
		generate_config_cache($config);
614
	}
615

    
616
	unlock($lockkey);
617

    
618
	if ($write_config_only) {
619
		/* tell kernel to sync fs data */
620
		conf_mount_ro();
621
		return $config;
622
	}
623

    
624
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
625

    
626
	/* tell kernel to sync fs data */
627
	conf_mount_ro();
628

    
629
	/* sync carp entries to other firewalls */
630
	carp_sync_client();
631

    
632
	if (is_dir("/usr/local/pkg/write_config")) {
633
		/* process packager manager custom rules */
634
		run_plugins("/usr/local/pkg/write_config/");
635
	}
636

    
637
	return $config;
638
}
639

    
640
/****f* config/reset_factory_defaults
641
 * NAME
642
 *   reset_factory_defaults - Reset the system to its default configuration.
643
 * RESULT
644
 *   integer	- indicates completion
645
 ******/
646
function reset_factory_defaults($lock = false, $reboot_required = true) {
647
	global $config, $g;
648

    
649
	conf_mount_rw();
650

    
651
	/* Remove all additional packages */
652
	mwexec("/bin/sh /usr/local/sbin/{$g['product_name']}-upgrade " .
653
	    "-r ALL_PACKAGES");
654

    
655
	if (!$lock) {
656
		$lockkey = lock('config', LOCK_EX);
657
	}
658

    
659
	/* create conf directory, if necessary */
660
	safe_mkdir($g['cf_conf_path']);
661

    
662
	/* clear out /conf */
663
	$dh = opendir($g['conf_path']);
664
	while ($filename = readdir($dh)) {
665
		if (($filename != ".") && ($filename != "..") &&
666
		    (!is_dir($g['conf_path'] . "/" . $filename))) {
667
			unlink_if_exists($g['conf_path'] . "/" . $filename);
668
		}
669
	}
670
	closedir($dh);
671
	unlink_if_exists($g['tmp_path'] . "/config.cache");
672

    
673
	/* copy default configuration */
674
	copy("{$g['conf_default_path']}/config.xml",
675
	    "{$g['cf_conf_path']}/config.xml");
676

    
677
	disable_security_checks();
678

    
679
	/*
680
	   Let write_config know that we are awaiting reload of the current config
681
	   to factory defaults. Either the system is about to reboot, throwing away
682
	   the current in-memory config as it shuts down, or the in-memory config
683
	   is about to be reloaded on-the-fly by parse_config.
684

    
685
	   In both cases, we want to ensure that write_config does not flush the
686
	   in-memory config back to disk.
687
	*/
688
	$config['reset_factory_defaults'] = true;
689

    
690
	/* call the wizard */
691
	if ($reboot_required) {
692
		// If we need a reboot first then touch a different trigger file.
693
		touch("/conf/trigger_initial_wizard_after_reboot");
694
	} else {
695
		touch("/conf/trigger_initial_wizard");
696
	}
697
	if (!$lock) {
698
		unlock($lockkey);
699
	}
700
	conf_mount_ro();
701
	setup_serial_port();
702
	return 0;
703
}
704

    
705
function config_restore($conffile) {
706
	global $config, $g;
707

    
708
	if (!file_exists($conffile)) {
709
		return 1;
710
	}
711

    
712
	backup_config();
713

    
714
	conf_mount_rw();
715

    
716
	$lockkey = lock('config', LOCK_EX);
717

    
718
	unlink_if_exists("{$g['tmp_path']}/config.cache");
719
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
720

    
721
	disable_security_checks();
722

    
723
	unlock($lockkey);
724

    
725
	$config = parse_config(true);
726

    
727
	conf_mount_ro();
728

    
729
	write_config(sprintf(gettext("Reverted to %s."), array_pop(explode("/", $conffile))), false);
730

    
731
	return 0;
732
}
733

    
734
function config_install($conffile) {
735
	global $config, $g;
736

    
737
	if (!file_exists($conffile)) {
738
		return 1;
739
	}
740

    
741
	if (!config_validate("{$conffile}")) {
742
		return 1;
743
	}
744

    
745
	if (platform_booting()) {
746
		echo gettext("Installing configuration...") . "\n";
747
	} else {
748
		log_error(gettext("Installing configuration ...."));
749
	}
750

    
751
	conf_mount_rw();
752
	$lockkey = lock('config', LOCK_EX);
753

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

    
756
	disable_security_checks();
757

    
758
	/* unlink cache file if it exists */
759
	if (file_exists("{$g['tmp_path']}/config.cache")) {
760
		unlink("{$g['tmp_path']}/config.cache");
761
	}
762

    
763
	unlock($lockkey);
764
	conf_mount_ro();
765

    
766
	return 0;
767
}
768

    
769
/*
770
 * Disable security checks for DNS rebind and HTTP referrer until next time
771
 * they pass (or reboot), to aid in preventing accidental lockout when
772
 * restoring settings like hostname, domain, IP addresses, and settings
773
 * related to the DNS rebind and HTTP referrer checks.
774
 * Intended for use when restoring a configuration or directly
775
 * modifying config.xml without an unconditional reboot.
776
 */
777
function disable_security_checks() {
778
	global $g;
779
	touch("{$g['tmp_path']}/disable_security_checks");
780
}
781

    
782
/* Restores security checks.  Should be called after all succeed. */
783
function restore_security_checks() {
784
	global $g;
785
	unlink_if_exists("{$g['tmp_path']}/disable_security_checks");
786
}
787

    
788
/* Returns status of security check temporary disable. */
789
function security_checks_disabled() {
790
	global $g;
791
	return file_exists("{$g['tmp_path']}/disable_security_checks");
792
}
793

    
794
function config_validate($conffile) {
795

    
796
	global $g, $xmlerr;
797

    
798
	$xml_parser = xml_parser_create();
799

    
800
	if (!($fp = fopen($conffile, "r"))) {
801
		$xmlerr = gettext("XML error: unable to open file");
802
		return false;
803
	}
804

    
805
	while ($data = fread($fp, 4096)) {
806
		if (!xml_parse($xml_parser, $data, feof($fp))) {
807
			$xmlerr = sprintf(gettext('%1$s at line %2$d'),
808
						xml_error_string(xml_get_error_code($xml_parser)),
809
						xml_get_current_line_number($xml_parser));
810
			return false;
811
		}
812
	}
813
	xml_parser_free($xml_parser);
814

    
815
	fclose($fp);
816

    
817
	return true;
818
}
819

    
820
function cleanup_backupcache($lock = false) {
821
	global $config, $g;
822
	$i = false;
823

    
824
	$revisions = intval(is_numericint($config['system']['backupcount']) ? $config['system']['backupcount'] : $g['default_config_backup_count']);
825

    
826
	if (!$lock) {
827
		$lockkey = lock('config');
828
	}
829

    
830
	conf_mount_rw();
831

    
832
	$backups = get_backups();
833
	if ($backups) {
834
		$baktimes = $backups['versions'];
835
		unset($backups['versions']);
836
	} else {
837
		$backups = array();
838
		$baktimes = array();
839
	}
840
	$newbaks = array();
841
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
842
	$tocache = array();
843

    
844
	foreach ($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
845
		$backupsize = filesize($backup);
846
		if ($backupsize == 0) {
847
			unlink($backup);
848
			continue;
849
		}
850
		$backupexp = explode('-', $backup);
851
		$backupexp = explode('.', array_pop($backupexp));
852
		$tocheck = array_shift($backupexp);
853
		unset($backupexp);
854
		if (!in_array($tocheck, $baktimes)) {
855
			$i = true;
856
			if (platform_booting()) {
857
				echo ".";
858
			}
859
			$newxml = parse_xml_config($backup, array($g['xml_rootobj'], 'pfsense'));
860
			if ($newxml == "-1") {
861
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
862
				unlink($backup);
863
				log_error(sprintf(gettext("The backup cache file %s is corrupted.  Unlinking."), $backup));
864
				continue;
865
			}
866
			if ($newxml['revision']['description'] == "") {
867
				$newxml['revision']['description'] = "Unknown";
868
			}
869
			if ($newxml['version'] == "") {
870
				$newxml['version'] = "?";
871
			}
872
			$tocache[$tocheck] = array('description' => $newxml['revision']['description'], 'version' => $newxml['version'], 'filesize' => $backupsize);
873
		}
874
	}
875
	foreach ($backups as $checkbak) {
876
		if (count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
877
			$newbaks[] = $checkbak;
878
		} else {
879
			$i = true;
880
			if (platform_booting()) print " " . $tocheck . "r";
881
		}
882
	}
883
	foreach ($newbaks as $todo) {
884
		$tocache[$todo['time']] = array('description' => $todo['description'], 'version' => $todo['version'], 'filesize' => $todo['filesize']);
885
	}
886
	if (is_int($revisions) and (count($tocache) > $revisions)) {
887
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
888
		foreach ($toslice as $sliced) {
889
			$newcache[$sliced] = $tocache[$sliced];
890
		}
891
		foreach ($tocache as $version => $versioninfo) {
892
			if (!in_array($version, array_keys($newcache))) {
893
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
894
			}
895
		}
896
		$tocache = $newcache;
897
	}
898
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
899
	fwrite($bakout, serialize($tocache));
900
	fclose($bakout);
901
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
902
	conf_mount_ro();
903

    
904
	if (!$lock) {
905
		unlock($lockkey);
906
	}
907
}
908

    
909
function get_backups() {
910
	global $g;
911
	if (file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
912
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
913
		$bakvers = array_keys($confvers);
914
		$toreturn = array();
915
		sort($bakvers);
916
		// 	$bakvers = array_reverse($bakvers);
917
		foreach (array_reverse($bakvers) as $bakver) {
918
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description'], 'version' => $confvers[$bakver]['version'], 'filesize' => $confvers[$bakver]['filesize']);
919
		}
920
	} else {
921
		return false;
922
	}
923
	$toreturn['versions'] = $bakvers;
924
	return $toreturn;
925
}
926

    
927
function backup_config() {
928
	global $config, $g;
929

    
930
	if ($g['platform'] == "cdrom") {
931
		return;
932
	}
933

    
934
	conf_mount_rw();
935

    
936
	/* Create backup directory if needed */
937
	safe_mkdir("{$g['cf_conf_path']}/backup");
938
	if ($config['revision']['time'] == "") {
939
		$baktime = 0;
940
	} else {
941
		$baktime = $config['revision']['time'];
942
	}
943

    
944
	if ($config['revision']['description'] == "") {
945
		$bakdesc = "Unknown";
946
	} else {
947
		$bakdesc = $config['revision']['description'];
948
	}
949

    
950
	$bakver = ($config['version'] == "") ? "?" : $config['version'];
951
	$bakfilename = $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml';
952
	copy($g['cf_conf_path'] . '/config.xml', $bakfilename);
953

    
954
	if (file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
955
		$backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
956
	} else {
957
		$backupcache = array();
958
	}
959
	$backupcache[$baktime] = array('description' => $bakdesc, 'version' => $bakver, 'filesize' => filesize($bakfilename));
960
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
961
	fwrite($bakout, serialize($backupcache));
962
	fclose($bakout);
963
	pfSense_fsync("{$g['cf_conf_path']}/backup/backup.cache");
964

    
965
	conf_mount_ro();
966

    
967
	return true;
968
}
969

    
970
function set_device_perms() {
971
	$devices = array(
972
		'pf' => array(
973
			'user' => 'root',
974
			'group' => 'proxy',
975
			'mode' => 0660),
976
		);
977

    
978
	foreach ($devices as $name => $attr) {
979
		$path = "/dev/$name";
980
		if (file_exists($path)) {
981
			chown($path, $attr['user']);
982
			chgrp($path, $attr['group']);
983
			chmod($path, $attr['mode']);
984
		}
985
	}
986
}
987

    
988
function get_config_user() {
989
	if (empty($_SESSION["Username"])) {
990
		$username = getenv("USER");
991
		if (empty($conuser) || $conuser == "root") {
992
			$username = "(system)";
993
		}
994
	} else {
995
		$username = $_SESSION["Username"];
996
	}
997

    
998
	if (!empty($_SERVER['REMOTE_ADDR'])) {
999
		$username .= '@' . $_SERVER['REMOTE_ADDR'];
1000
	}
1001

    
1002
	return $username;
1003
}
1004

    
1005
function make_config_revision_entry($desc = null, $override_user = null) {
1006
	if (empty($override_user)) {
1007
		$username = get_config_user();
1008
	} else {
1009
		$username = $override_user;
1010
	}
1011

    
1012
	$revision = array();
1013

    
1014
	if (time() > mktime(0, 0, 0, 9, 1, 2004)) {     /* make sure the clock settings are plausible */
1015
		$revision['time'] = time();
1016
	}
1017

    
1018
	/* Log the running script so it's not entirely unlogged what changed */
1019
	if ($desc == "Unknown") {
1020
		$desc = sprintf(gettext("%s made unknown change"), $_SERVER['SCRIPT_NAME']);
1021
	}
1022
	if (!empty($desc)) {
1023
		$revision['description'] = "{$username}: " . $desc;
1024
	}
1025
	$revision['username'] = $username;
1026
	return $revision;
1027
}
1028

    
1029
function pfSense_clear_globals() {
1030
	global $config, $FilterIfList, $GatewaysList, $filterdns, $aliases, $aliastable;
1031

    
1032
	$error = error_get_last();
1033

    
1034
	// Errors generated by user code (diag_commands.php) are identified by path and not added to notices
1035
	if ($error !== NULL && !preg_match('|^' . preg_quote($g['tmp_path_user_code']) . '/[^/]{1,16}$|', $error['file'])) {
1036
		if (in_array($error['type'], array(E_ERROR, E_COMPILE_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR))) {
1037
			$errorstr = "PHP ERROR: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
1038
			print($errorstr);
1039
			log_error($errorstr);
1040
			file_notice("phperror", $errorstr, 'PHP errors');
1041
		} else if ($error['type'] != E_NOTICE) {
1042
			$errorstr = "PHP WARNING: Type: {$error['type']}, File: {$error['file']}, Line: {$error['line']}, Message: {$error['message']}";
1043
			// XXX: comment out for now, should re-enable post-2.2
1044
			//print($errorstr);
1045
			//log_error($errorstr);
1046
			//file_notice("phpwarning", $errorstr, 'PHP warning');
1047
		}
1048
	}
1049

    
1050
	if (isset($FilterIfList)) {
1051
		unset($FilterIfList);
1052
	}
1053

    
1054
	if (isset($GatewaysList)) {
1055
		unset($GatewaysList);
1056
	}
1057

    
1058
	/* Used for the hostname dns resolver */
1059
	if (isset($filterdns)) {
1060
		unset($filterdns);
1061
	}
1062

    
1063
	/* Used for aliases and interface macros */
1064
	if (isset($aliases)) {
1065
		unset($aliases);
1066
	}
1067
	if (isset($aliastable)) {
1068
		unset($aliastable);
1069
	}
1070

    
1071
	unset($config);
1072
}
1073

    
1074
register_shutdown_function('pfSense_clear_globals');
1075

    
1076
?>
(14-14/67)