Project

General

Profile

Download (36.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/****h* pfSense/config
3
 * NAME
4
 *   config.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.inc
12
	Copyright (C) 2004-2006 Scott Ullrich
13
	All rights reserved.
14

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

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

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

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

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

    
46
if($g['booting']) echo ".";
47

    
48
/* do not load this file twice. */
49
if($config_inc_loaded == true)
50
	return;
51
else
52
	$config_inc_loaded = true;
53

    
54
/* include globals/utility/XML parser files */
55
require_once("globals.inc");
56
if($g['booting']) echo ".";
57
require_once("util.inc");
58
if($g['booting']) echo ".";
59
require_once("xmlparse.inc");
60
if($g['booting']) echo ".";
61
require_once("crypt.inc");
62

    
63
/* read platform */
64
if($g['booting']) echo ".";
65
if (file_exists("{$g['etc_path']}/platform")) {
66
	$g['platform'] = chop(file_get_contents("{$g['etc_path']}/platform"));
67
} else {
68
	$g['platform'] = "unknown";
69
}
70

    
71
/* if /debugging exists, lets set $debugging
72
   so we can output more information */
73
if(file_exists("/debugging")) {
74
	$debugging = true;
75
	$g['debug'] = true;
76
}
77

    
78
if($g['booting']) echo ".";
79
if(file_exists("/cf/conf/config.xml")) {
80
	$config_contents = file_get_contents("/cf/conf/config.xml");
81
	if(stristr($config_contents, "<m0n0wall>") == true) {
82
		if($g['booting']) echo ".";
83
		/* user has just upgraded to m0n0wall, replace root xml tags */
84
		log_error("Upgrading m0n0wall configuration to pfSense... ");
85
		$config_contents = str_replace("m0n0wall","pfsense", $config_contents);
86
		if (!config_validate("{$g['conf_path']}/config.xml"))
87
			log_error("ERROR!  Could not convert m0n0wall -> pfsense in config.xml");
88
		conf_mount_rw();
89
		$fd = fopen("/cf/conf/config.xml", "w");
90
		fwrite($fd, $config_contents);
91
		fclose($fd);
92
		conf_mount_ro();
93
	}
94
}
95

    
96
/* if our config file exists bail out, we're already set. */
97
if ($g['booting'] and !file_exists($g['cf_conf_path'] . "/config.xml")  ) {
98
	if($g['booting']) echo ".";
99
	/* find the device where config.xml resides and write out an fstab */
100
	unset($cfgdevice);
101
	if($g['booting']) echo ".";
102
	/* check if there's already an fstab (NFS booting?) */
103
	if (!file_exists("{$g['etc_path']}/fstab")) {
104
		if($g['booting']) echo ".";
105
		if (strstr($g['platform'], "cdrom")) {
106
			/* config is on floppy disk for CD-ROM version */
107
			$cfgdevice = $cfgpartition = "fd0";
108
			$dmesg = `dmesg -a`;
109
			if(ereg("da0", $dmesg) == true) {
110
				$cfgdevice = $cfgpartition = "da0" ;
111
				if (mwexec("/sbin/mount -r /dev/{$cfgdevice} /cf")) {
112
					/* could not mount, fallback to floppy */
113
					$cfgdevice = $cfgpartition = "fd0";
114
				}
115
			}
116
			$cfgfstype = "msdosfs";
117
			echo "CDROM build\n";
118
			echo "   CFG: {$cfgpartition}\n";
119
			echo "  TYPE: {$cfgfstype}\n";
120
		} else {
121
			if($g['booting']) echo ".";
122
			/* probe kernel known disks until we find one with config.xml */
123
			$disks = explode(" ", trim(preg_replace("/kern.disks: /", "", exec("/sbin/sysctl kern.disks"))));
124
			foreach ($disks as $mountdisk) {
125
				/* skip mfs mounted filesystems */
126
				if (strstr($mountdisk, "md"))
127
					continue;
128
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}a {$g['cf_path']}") == 0) {
129
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
130
						/* found it */
131
						$cfgdevice = $mountdisk;
132
						$cfgpartition = $cfgdevice . "a";
133
						$cfgfstype = "ufs";
134
						echo "Found configuration on $cfgdevice.\n";
135
					}
136

    
137
					mwexec("/sbin/umount -f {$g['cf_path']}");
138

    
139
					if ($cfgdevice)
140
						break;
141
				}
142
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}d {$g['cf_path']}") == 0) {
143
					if($g['booting']) echo ".";
144
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
145
						/* found it */
146
						$cfgdevice = $mountdisk;
147
						$cfgpartition = $cfgdevice . "d";
148
						$cfgfstype = "ufs";
149
						echo "Found configuration on $cfgdevice.\n";
150
					}
151

    
152
					mwexec("/sbin/umount -f {$g['cf_path']}");
153

    
154
					if ($cfgdevice)
155
						break;
156
				}
157
			}
158
		}
159
		if($g['booting']) echo ".";
160
		if (!$cfgdevice) {
161
			$last_backup = discover_last_backup();
162
			if($last_backup) {
163
				log_error("No config.xml found, attempting last known config restore.");
164
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
165
				restore_backup("/cf/conf/backup/{$last_backup}");
166
			} else {
167
				log_error("No config.xml or config backups found, resetting to factory defaults.");
168
				restore_backup('/conf.default/config.xml');
169
			}
170
		}
171

    
172
		/* write device name to a file for rc.firmware */
173
		$fd = fopen("{$g['varetc_path']}/cfdevice", "w");
174
		fwrite($fd, $cfgdevice . "\n");
175
		fclose($fd);
176

    
177
		/* write out an fstab */
178
		$fd = fopen("{$g['etc_path']}/fstab", "w");
179

    
180
		$fstab = "/dev/{$cfgpartition} {$g['cf_path']} {$cfgfstype} ro 1 1\n";
181
		$fstab .= "proc /proc procfs rw 0 0\n";
182

    
183
		fwrite($fd, $fstab);
184
		fclose($fd);
185
	}
186
	if($g['booting']) echo ".";
187
	/* mount all filesystems */
188
	mwexec("/sbin/mount -a");
189
}
190

    
191
/****f* config/encrypted_configxml
192
 * NAME
193
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
194
 * INPUTS
195
 *   None
196
 * RESULT
197
 *   $config 	- rewrites config.xml without encryption
198
 ******/
199
function encrypted_configxml() {
200
	global $g, $config;
201
	if(file_exists($g['conf_path'] . "/config.xml")) {
202
		if($g['booting']) {
203
			$configtxt = file_get_contents($g['conf_path'] . "/config.xml");			
204
			if(tagfile_deformat($configtxt, $configtxt, "config.xml")) {
205
				$fp = fopen('php://stdin', 'r');
206
				$data = "";
207
				echo "\n\n*** Encrypted config.xml detected ***\n";
208
				while($data == "") {
209
					echo "\nEnter the password to decrypt config.xml: ";
210
					$decrypt_password = chop(fgets($fp));
211
					$data = decrypt_data($configtxt, $decrypt_password);
212
					if(!strstr($data, "<pfsense>"))
213
						$data = "";
214
					if($data) {
215
						$fd = fopen($g['conf_path'] . "/config.xml", "w");
216
						fwrite($fd, $data);
217
						fclose($fd);
218
						echo "\nConfig.xml unlocked.\n";
219
						fclose($fp);
220
					} else {
221
						echo "\nInvalid password entered.  Please try again.\n";
222
					}
223
				}
224
			}
225
		}
226
	}
227
}
228

    
229
/****f* config/parse_config
230
 * NAME
231
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
232
 * INPUTS
233
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
234
 * RESULT
235
 *   $config      - array containing all configuration variables
236
 ******/
237
function parse_config($parse = false) {
238
	global $g;
239
	
240
	$lockkey = lock('config');
241
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
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", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
246
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
247
		} else {
248
			unlock($lockkey);
249
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
250
		}
251
	}
252
	if($g['booting']) echo ".";
253
	// Check for encrypted config.xml
254
	encrypted_configxml();
255
	if(!$parse) {
256
		if(file_exists($g['tmp_path'] . '/config.cache')) {
257
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
258
			if(is_null($config)) {
259
				unlock($lockkey);
260
				parse_config(true);
261
			}
262
		} else {
263
			if(!file_exists($g['conf_path'] . "/config.xml")) {
264
				log_error("No config.xml found, attempting last known config restore.");
265
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
266
				$last_backup = discover_last_backup();
267
				if ($last_backup)
268
					restore_backup("/cf/conf/backup/{$last_backup}");
269
				else
270
					log_error("Could not restore config.xml.");
271
			}
272
			unlock($lockkey);
273
			$config = parse_config(true);
274
			$lockkey = lock('config');
275
		}
276
	} else {
277
		if(!file_exists($g['conf_path'] . "/config.xml")) {
278
			if($g['booting']) echo ".";
279
			log_error("No config.xml found, attempting last known config restore.");
280
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
281
			$last_backup = discover_last_backup();
282
			if ($last_backup)
283
				restore_backup("/cf/conf/backup/{$last_backup}");
284
			else
285
				log_error("Could not restore config.xml.");
286
		}
287
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
288
		if($config == "-1") {
289
			$last_backup = discover_last_backup();
290
			if ($last_backup)
291
				restore_backup("/cf/conf/backup/{$last_backup}");
292
			else
293
				log_error(gettext("Could not restore config.xml."));
294
		}
295
		generate_config_cache($config);
296
	}
297
	if($g['booting']) echo ".";
298
	alias_make_table($config);
299
	unlock($lockkey);
300

    
301
	/* process packager manager custom rules */
302
	if(is_dir("/usr/local/pkg/config_parse/")) {
303
		update_filter_reload_status("Running plugins (config_parse)");
304
		run_plugins("/usr/local/pkg/config_parse/");
305
		update_filter_reload_status("Plugins completed.");
306
	}
307

    
308
	return $config;
309
}
310

    
311
/****f* config/generate_config_cache
312
 * NAME
313
 *   generate_config_cache - Write serialized configuration to cache.
314
 * INPUTS
315
 *   $config	- array containing current firewall configuration
316
 * RESULT
317
 *   boolean	- true on completion
318
 ******/
319
function generate_config_cache($config) {
320
	global $g;
321

    
322
	conf_mount_rw();
323
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
324
	fwrite($configcache, serialize($config));
325
	fclose($configcache);
326
	conf_mount_ro();
327
}
328

    
329
function discover_last_backup() {
330
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
331
	$last_backup = "";
332
        foreach($backups as $backup)
333
        	if($backup)
334
	        	$last_backup = $backup;
335

    
336
        return $last_backup;
337
}
338

    
339
function restore_backup($file) {
340
	if (file_exists($file)) {
341
		conf_mount_rw();
342
		copy("$file","/cf/conf/config.xml");
343
		unlink_if_exists("/tmp/config.cache");
344
		log_error("{$g['product_name']} is restoring the configuration $file");
345
		file_notice("config.xml", "{$g['product_name']} is restoring the configuration $file", "pfSenseConfigurator", "");
346
		conf_mount_ro();
347
	}
348
}
349

    
350
/****f* config/parse_config_bootup
351
 * NAME
352
 *   parse_config_bootup - Bootup-specific configuration checks.
353
 * RESULT
354
 *   null
355
 ******/
356
function parse_config_bootup() {
357
	global $config, $g, $noparseconfig;
358

    
359
	if($g['booting']) echo ".";
360

    
361
	$lockkey = lock('config');
362
	if (!$noparseconfig) {
363
		if (!file_exists("{$g['conf_path']}/config.xml")) {
364
			if ($g['booting']) {
365
				if (strstr($g['platform'], "cdrom")) {
366
					/* try copying the default config. to the floppy */
367
					echo "Resetting factory defaults...\n";
368
					reset_factory_defaults(true);
369
					if (file_exists("{$g['conf_path']}/config.xml")) {
370
						/* do nothing, we have a file. */
371
					} else {
372
						echo "No XML configuration file found - using factory defaults.\n";
373
						echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
374
						echo "file is inserted. If it isn't, your configuration changes will be lost\n";
375
						echo "on reboot.\n";
376
					}
377
				} else {
378
					$last_backup = discover_last_backup();
379
					if($last_backup) {
380
						log_error("No config.xml found, attempting last known config restore.");
381
						file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
382
						restore_backup("/cf/conf/backup/{$last_backup}");
383
					}
384
					if(!file_exists("{$g['conf_path']}/config.xml")) {
385
						echo "XML configuration file not found.  {$g['product_name']} cannot continue booting.\n";
386
						mwexec("/sbin/halt");
387
						exit;
388
					}
389
					log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
390
					file_notice("config.xml", "Last known config found and restored.  Please double check your configuration file for accuracy.", "pfSenseConfigurator", "");
391
				}
392
			} else {
393
				unlock($lockkey);
394
				exit(0);
395
			}
396
		}
397
	}
398
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
399
		$last_backup = discover_last_backup();
400
		if($last_backup) {
401
			log_error("No config.xml found, attempting last known config restore.");
402
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
403
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
404
		} else {
405
			unlock($lockkey);
406
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
407
		}
408
	}
409
	unlock($lockkey);
410
	parse_config(true);
411

    
412
	if ((float)$config['version'] > (float)$g['latest_config']) {
413
		echo <<<EOD
414

    
415

    
416
*******************************************************************************
417
* WARNING!                                                                    *
418
* The current configuration has been created with a newer version of {$g['product_name']}  *
419
* than this one! This can lead to serious misbehavior and even security       *
420
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
421
* revert to the default configuration immediately!                            *
422
*******************************************************************************
423

    
424

    
425
EOD;
426
		}
427

    
428
	/* make alias table (for faster lookups) */
429
	alias_make_table($config);
430
}
431

    
432
/****f* config/conf_mount_rw
433
 * NAME
434
 *   conf_mount_rw - Mount filesystems read/write.
435
 * RESULT
436
 *   null
437
 ******/
438
/* mount flash card read/write */
439
function conf_mount_rw() {
440
	global $g;
441

    
442
	/* do not mount on cdrom platform */
443
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
444
		return;
445
		
446
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
447
	if($status <> 0) {
448
		if($g['booting'])
449
			echo "Disk is dirty.  Running fsck -y\n";
450
		mwexec("/sbin/fsck -y {$g['cf_path']}");
451
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
452
	}
453

    
454
	/*    if the platform is soekris or wrap or pfSense, lets mount the
455
	 *    compact flash cards root.
456
         */
457
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
458
	   or $g['platform'] == "embedded") {
459
		$status = mwexec("/sbin/mount -u -w /");
460
		/* we could not mount this correctly.  kick off fsck */
461
		if($status <> 0) {
462
			log_error("File system is dirty.  Launching FSCK for /");
463
			mwexec("/sbin/fsck -y /");
464
			$status = mwexec("/sbin/mount -u -w /");
465
		}
466
	}
467
}
468

    
469
/****f* config/conf_mount_ro
470
 * NAME
471
 *   conf_mount_ro - Mount filesystems readonly.
472
 * RESULT
473
 *   null
474
 ******/
475
function conf_mount_ro() {
476
	global $g;
477

    
478
	if($g['booting'] == true)
479
		return;
480

    
481
	/* firmare upgrade in progress */
482
	if(file_exists($g['varrun_path'] . "/firmware.lock"))
483
		return;
484

    
485
	/* do not umount if generating ssh keys */
486
	if(file_exists("/tmp/keys_generating"))
487
		return;
488

    
489
	/* do not umount on cdrom or pfSense platforms */
490
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
491
		return;
492

    
493
	/* sync data, then force a remount of /cf */
494
	mwexec("/bin/sync");
495
	mwexec("/bin/sync");
496
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
497
	mwexec("/sbin/mount -u -r -f /");
498
}
499

    
500
/****f* config/convert_config
501
 * NAME
502
 *   convert_config - Attempt to update config.xml.
503
 * DESCRIPTION
504
 *   convert_config() reads the current global configuration
505
 *   and attempts to convert it to conform to the latest
506
 *   config.xml version. This allows major formatting changes
507
 *   to be made with a minimum of breakage.
508
 * RESULT
509
 *   null
510
 ******/
511
/* convert configuration, if necessary */
512
function convert_config() {
513
	global $config, $g;
514
	$now = date("H:i:s");
515
	log_error("Start Configuration upgrade at $now, set execution timeout to 15 minutes");
516
	ini_set("max_execution_time", "900");
517

    
518
	/* special case upgrades */
519
	/* fix every minute crontab bogons entry */
520
	$cron_item_count = count($config['cron']['item']);
521
	for($x=0; $x<$cron_item_count; $x++) {
522
		if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
523
			if($config['cron']['item'][$x]['hour'] == "*" ) {
524
		        $config['cron']['item'][$x]['hour'] = "3";
525
		 		write_config("Updated bogon update frequency to 3am");
526
		 		log_error("Updated bogon update frequency to 3am");
527
		 	}       
528
		}
529
	}
530
	if ($config['version'] == $g['latest_config'])
531
		return;		/* already at latest version */
532

    
533
	// Save off config version
534
	$prev_version = $config['version'];
535
	
536
	include_once('upgrade_config.inc');
537
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
538
	while ($config['version'] < $g['latest_config']) {
539
		$cur = $config['version'] * 10;
540
		$next = $cur + 1;
541
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
542
		$migration_function();
543
		$config['version'] = sprintf('%.1f', $next / 10);
544
		echo ".";
545
	}
546

    
547
	$now = date("H:i:s");
548
	log_error("Ended Configuration upgrade at $now");
549

    
550
	if ($prev_version != $config['version'])
551
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
552
}
553

    
554
/****f* config/write_config
555
 * NAME
556
 *   write_config - Backup and write the firewall configuration.
557
 * DESCRIPTION
558
 *   write_config() handles backing up the current configuration,
559
 *   applying changes, and regenerating the configuration cache.
560
 * INPUTS
561
 *   $desc	- string containing the a description of configuration changes
562
 *   $backup	- boolean: do not back up current configuration if false.
563
 * RESULT
564
 *   null
565
 ******/
566
/* save the system configuration */
567
function write_config($desc="Unknown", $backup = true) {
568
	global $config, $g;
569

    
570
	if($g['bootup']) 
571
		log_error("WARNING! Configuration written on bootup.  This can cause stray openvpn and load balancing items in config.xml");
572

    
573
	if($backup)
574
		backup_config();
575

    
576
	if (time() > mktime(0, 0, 0, 9, 1, 2004))       /* make sure the clock settings are plausible */
577
		$changetime = time();
578

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

    
583
	$config['revision']['description'] = $desc;
584
	$config['revision']['time'] = $changetime;
585

    
586
	$lockkey = lock('config');
587

    
588
	/* generate configuration XML */
589
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
590

    
591
	conf_mount_rw();
592

    
593
	/* write new configuration */
594
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
595
        if (!$fd) {
596
                // Unable to open temporary file for writing
597
		log_error("WARNING: Config contents could not be save. Could not open file!");
598
		unlock($lockkey);
599
                return false;
600
        }
601
        if (!fwrite($fd, $xmlconfig)) {
602
                // Unable to write to temporary file
603
		log_error("WARNING: Config contents could not be written on file.");
604
                fclose($fd);
605
		unlock($lockkey);
606
                return false;
607
        }
608
        fclose($fd);
609

    
610
	if($g['platform'] == "embedded") {
611
		cleanup_backupcache(5, false);
612
	} else {
613
		cleanup_backupcache(30, false);
614
	}
615

    
616
	/* re-read configuration */
617
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
618

    
619
	/* write config cache */
620
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
621
	if ($fd) {
622
		fwrite($fd, serialize($config));
623
		fclose($fd);
624
	}
625

    
626
	/* tell kernel to sync fs data */
627
	if (!$g['booting'])
628
		conf_mount_ro();
629
	unlock($lockkey);
630

    
631
	if(is_dir("/usr/local/pkg/write_config/")) {
632
		/* process packager manager custom rules */
633
		update_filter_reload_status("Running plugins");
634
		run_plugins("/usr/local/pkg/write_config/");
635
		update_filter_reload_status("Plugins completed.");
636
	}
637

    
638
	return $config;
639
}
640

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

    
650
	if ($lock)
651
		$lockkey = lock('config');
652
	conf_mount_rw();
653

    
654
	/* create conf directory, if necessary */
655
	safe_mkdir("{$g['cf_conf_path']}");
656

    
657
	/* clear out /conf */
658
	$dh = opendir($g['conf_path']);
659
	while ($filename = readdir($dh)) {
660
		if (($filename != ".") && ($filename != "..")) {
661
			unlink_if_exists($g['conf_path'] . "/" . $filename);
662
		}
663
	}
664
	closedir($dh);
665

    
666
	/* copy default configuration */
667
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
668

    
669
	/* call the wizard */
670
	touch("/conf/trigger_initial_wizard");
671
	conf_mount_ro();
672
	if ($lock)
673
		unlock($lockkey);
674

    
675
	return 0;
676
}
677

    
678
function config_restore($conffile) {
679
	global $config, $g;
680

    
681
	if (!file_exists($conffile))
682
		return 1;
683

    
684
	$lockkey = lock('config');
685
	conf_mount_rw();
686

    
687
	backup_config();
688
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
689
	$config = parse_config(true);
690
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
691

    
692
	conf_mount_ro();
693
	unlock($lockkey);
694

    
695
	return 0;
696
}
697

    
698
function config_install($conffile) {
699
	global $config, $g;
700

    
701
	if (!file_exists($conffile))
702
		return 1;
703

    
704
	if (!config_validate("{$g['conf_path']}/config.xml"))
705
		return 1;
706

    
707
	if($g['booting'] == true)
708
		echo "Installing configuration...\n";
709

    
710
	$lockkey = lock('config');
711
	conf_mount_rw();
712

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

    
715
	/* unlink cache file if it exists */
716
	if(file_exists("{$g['tmp_path']}/config.cache"))
717
		unlink("{$g['tmp_path']}/config.cache");
718

    
719
	conf_mount_ro();
720
	unlock($lockkey);
721

    
722
    return 0;
723
}
724

    
725
function config_validate($conffile) {
726

    
727
	global $g, $xmlerr;
728

    
729
	$xml_parser = xml_parser_create();
730

    
731
	if (!($fp = fopen($conffile, "r"))) {
732
		$xmlerr = "XML error: unable to open file";
733
		return false;
734
	}
735

    
736
	while ($data = fread($fp, 4096)) {
737
		if (!xml_parse($xml_parser, $data, feof($fp))) {
738
			$xmlerr = sprintf("%s at line %d",
739
						xml_error_string(xml_get_error_code($xml_parser)),
740
						xml_get_current_line_number($xml_parser));
741
			return false;
742
		}
743
	}
744
	xml_parser_free($xml_parser);
745

    
746
	fclose($fp);
747

    
748
	return true;
749
}
750

    
751
function set_networking_interfaces_ports() {
752
	global $noreboot;
753
	global $config;
754
	global $g;
755
	global $fp;
756

    
757
	$fp = fopen('php://stdin', 'r');
758

    
759
	$memory = get_memory();
760
	$avail = $memory[0];
761

    
762
	if($avail < $g['minimum_ram_warning']) {
763
		echo "\n\n\n";
764
		echo "DANGER!  WARNING!  ACHTUNG!\n\n";
765
		echo "{$g['product_name']} requires *AT LEAST* {$g['minimum_ram_warning_text']} RAM to function correctly.\n";
766
		echo "Only ({$avail}) MB RAM has been detected.\n";
767
		echo "\nPress ENTER to continue. ";
768
		fgets($fp);
769
		echo "\n";
770
	}
771

    
772
	$iflist = get_interface_list();
773

    
774
	echo <<<EOD
775

    
776
Valid interfaces are:
777

    
778

    
779
EOD;
780

    
781
	if(!is_array($iflist)) {
782
		echo "No interfaces found!\n";
783
		$iflist = array();
784
	} else {
785
		foreach ($iflist as $iface => $ifa) {
786
			echo sprintf("% -8s%s%s\t%s\n", $iface, $ifa['mac'],
787
				$ifa['up'] ? "   (up)" : "   (down)", $ifa['dmesg']);
788
		}
789
	}
790

    
791
	echo <<<EOD
792

    
793
Do you want to set up VLANs first?
794
If you are not going to use VLANs, or only for optional interfaces, you should
795
say no here and use the webConfigurator to configure VLANs later, if required.
796

    
797
Do you want to set up VLANs now [y|n]?
798
EOD;
799

    
800
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
801
		vlan_setup();
802

    
803
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
804

    
805
		echo "\n\nVLAN interfaces:\n\n";
806
		foreach ($config['vlans']['vlan'] as $vlan) {
807

    
808
			echo sprintf("% -8s%s\n", "vlan{$vlan['tag']}",
809
				"VLAN tag {$vlan['tag']}, interface {$vlan['if']}");
810

    
811
			$iflist['vlan' . $vlan['tag']] = array();
812
		}
813
	}
814

    
815
	echo <<<EOD
816

    
817
*NOTE*  {$g['product_name']} requires {$g['minimum_nic_count_text']} assigned interfaces to function.
818
        If you do not have {$g['minimum_nic_count_text']} interfaces you CANNOT continue. 
819

    
820
        If you do not have at least {$g['minimum_nic_count']} *REAL* network interface cards
821
        or one interface with multiple VLANs then {$g['product_name']}
822
        *WILL NOT* function correctly.
823

    
824
If you do not know the names of your interfaces, you may choose to use
825
auto-detection. In that case, disconnect all interfaces now before
826
hitting 'a' to initiate auto detection.
827

    
828
EOD;
829

    
830
	do {
831
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
832
		$wanif = chop(fgets($fp));
833
		if ($wanif === "") {
834
			return;
835
		}
836
		if ($wanif === "a")
837
			$wanif = autodetect_interface("WAN", $fp);
838
		else if (!array_key_exists($wanif, $iflist)) {
839
			echo "\nInvalid interface name '{$wanif}'\n";
840
			unset($wanif);
841
			continue;
842
		}
843
	} while (!$wanif);
844

    
845
	do {
846
		echo "\nEnter the LAN interface name or 'a' for auto-detection \n" .
847
		    "NOTE: this enables full Firewalling/NAT mode.\n" .
848
			"(or nothing if finished): ";
849

    
850
		$lanif = chop(fgets($fp));
851
		
852
		if($lanif == "exit") {
853
			exit;
854
		}
855
		
856
		if($lanif == "") {
857
			if($g['minimum_nic_count'] < 2) {
858
				break;	
859
			} else {
860
				fclose($fp);
861
				return;
862
			}
863
		}
864

    
865
		if ($lanif === "a")
866
			$lanif = autodetect_interface("LAN", $fp);
867
		else if (!array_key_exists($lanif, $iflist)) {
868
			echo "\nInvalid interface name '{$lanif}'\n";
869
			unset($lanif);
870
			continue;
871
		}
872
	} while (!$lanif);
873

    
874
	/* optional interfaces */
875
	$i = 0;
876
	$optif = array();
877

    
878
	if($lanif <> "") {
879
		while (1) {
880
			if ($optif[$i])
881
				$i++;
882
			$i1 = $i + 1;
883
	
884
			if($config['interfaces']['opt' . $i1]['descr'])
885
				echo "\nOptional interface {$i1} description found: {$config['interfaces']['opt' . $i1]['descr']}";
886

    
887
			echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
888
				"(or nothing if finished): ";
889
	
890
			$optif[$i] = chop(fgets($fp));
891
	
892
			if ($optif[$i]) {
893
				if ($optif[$i] === "a") {
894
					$ad = autodetect_interface("Optional " . $i1, $fp);
895
					if ($ad)
896
						$optif[$i] = $ad;
897
					else
898
						unset($optif[$i]);
899
				} else if (!array_key_exists($optif[$i], $iflist)) {
900
					echo "\nInvalid interface name '{$optif[$i]}'\n";
901
					unset($optif[$i]);
902
					continue;
903
				}
904
			} else {
905
				unset($optif[$i]);
906
				break;
907
			}
908
		}
909
	}
910
	
911
	/* check for double assignments */
912
	$ifarr = array_merge(array($lanif, $wanif), $optif);
913
	
914
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
915
	for ($j = ($i+1); $j < count($ifarr); $j++) {
916
		if ($ifarr[$i] == $ifarr[$j]) {
917
			echo <<<EOD
918

    
919
Error: you cannot assign the same interface name twice!
920

    
921
EOD;
922
				fclose($fp);
923
				return;
924
			}
925
		}
926
	}
927

    
928
	echo "\nThe interfaces will be assigned as follows: \n\n";
929

    
930
	if ($lanif != "")
931
		echo "LAN  ->" . $lanif . "\n";
932
	echo "WAN  ->" . $wanif . "\n";
933
	for ($i = 0; $i < count($optif); $i++) {
934
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
935
	}
936

    
937
echo <<<EOD
938

    
939
Do you want to proceed [y|n]?
940
EOD;
941

    
942
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
943
		if($lanif) {
944
			$config['interfaces']['lan']['if'] = $lanif;
945
		} elseif (!$g['booting']) {
946

    
947
echo <<<EODD
948

    
949
You have chosen to remove the LAN interface.
950

    
951
Would you like to remove the LAN IP address and
952
unload the interface now? [y|n]? 
953
EODD;
954

    
955
				if (strcasecmp(chop(fgets($fp)), "y") == 0) {
956
					if($config['interfaces']['lan']['if'])
957
						mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
958
				}
959
				if(isset($config['interfaces']['lan']))
960
					unset($config['interfaces']['lan']);
961
				if(isset($config['dhcpd']['lan']))
962
					unset($config['dhcpd']['lan']);
963
				if(isset($config['interfaces']['lan']['if']))
964
					unset($config['interfaces']['lan']['if']);
965
				if(isset($config['interfaces']['wan']['blockpriv']))
966
					unset($config['interfaces']['wan']['blockpriv']);
967
				if(isset($config['shaper']))
968
					unset($config['shaper']);
969
				if(isset($config['ezshaper']))
970
					unset($config['ezshaper']);
971
				if(isset($config['nat']))
972
					unset($config['nat']);				
973
		} else {
974
			if(isset($config['interfaces']['lan']['if']))
975
				mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
976
			if(isset($config['interfaces']['lan']))
977
				unset($config['interfaces']['lan']);
978
			if(isset($config['dhcpd']['lan']))
979
				unset($config['dhcpd']['lan']);
980
			if(isset($config['interfaces']['lan']['if']))
981
				unset($config['interfaces']['lan']['if']);
982
			if(isset($config['interfaces']['wan']['blockpriv']))
983
				unset($config['interfaces']['wan']['blockpriv']);
984
			if(isset($config['shaper']))
985
				unset($config['shaper']);
986
			if(isset($config['ezshaper']))
987
				unset($config['ezshaper']);
988
			if(isset($config['nat']))
989
				unset($config['nat']);				
990
		}
991
		if (preg_match($g['wireless_regex'], $lanif)) {
992
			if (!is_array($config['interfaces']['lan']['wireless']))
993
				$config['interfaces']['lan']['wireless'] = array();
994
		} else {
995
			unset($config['interfaces']['lan']['wireless']);
996
		}
997

    
998
		$config['interfaces']['wan']['if'] = $wanif;
999
		if (preg_match($g['wireless_regex'], $wanif)) {
1000
			if (!is_array($config['interfaces']['wan']['wireless']))
1001
				$config['interfaces']['wan']['wireless'] = array();
1002
		} else {
1003
			unset($config['interfaces']['wan']['wireless']);
1004
		}
1005

    
1006
		for ($i = 0; $i < count($optif); $i++) {
1007
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1008
				$config['interfaces']['opt' . ($i+1)] = array();
1009

    
1010
			$config['interfaces']['opt' . ($i+1)]['if'] = $optif[$i];
1011

    
1012
			/* wireless interface? */
1013
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1014
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1015
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1016
			} else {
1017
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1018
			}
1019

    
1020
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1021
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1022
		}
1023

    
1024
		/* remove all other (old) optional interfaces */
1025
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1026
			unset($config['interfaces']['opt' . ($i+1)]);
1027

    
1028
		echo "\nWriting configuration...";
1029
		write_config();
1030
		echo "done.\n";
1031

    
1032
		echo <<<EOD
1033

    
1034

    
1035

    
1036
EOD;
1037

    
1038
		fclose($fp);
1039
		if($g['booting'])
1040
			return;
1041

    
1042
		echo "One moment while we reload the settings...";
1043

    
1044
		$g['booting'] = false;
1045

    
1046
		/* XXX: ermal - disable it for now this is used during bootup at best so shouldn't be needed.
1047
		 * 		For now just comment it out and later remove it completely.
1048
		 * resync everything 
1049
			reload_all_sync();
1050
		 */
1051

    
1052
		echo " done!\n";
1053

    
1054
		touch("{$g['tmp_path']}/assign_complete");
1055

    
1056
	}
1057
}
1058

    
1059
function autodetect_interface($ifname, $fp) {
1060
	$iflist_prev = get_interface_list("media");
1061
	echo <<<EOD
1062

    
1063
Connect the {$ifname} interface now and make sure that the link is up.
1064
Then press ENTER to continue.
1065

    
1066
EOD;
1067
	fgets($fp);
1068
	$iflist = get_interface_list("media");
1069

    
1070
	foreach ($iflist_prev as $ifn => $ifa) {
1071
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1072
			echo "Detected link-up on interface {$ifn}.\n";
1073
			return $ifn;
1074
		}
1075
	}
1076

    
1077
	echo "No link-up detected.\n";
1078

    
1079
	return null;
1080
}
1081

    
1082
function vlan_setup() {
1083
	global $iflist, $config, $g, $fp;
1084

    
1085
	$iflist = get_interface_list();
1086

    
1087
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1088

    
1089
	echo <<<EOD
1090

    
1091
WARNING: all existing VLANs will be cleared if you proceed!
1092

    
1093
Do you want to proceed [y|n]?
1094
EOD;
1095

    
1096
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1097
		return;
1098
	}
1099

    
1100
	$config['vlans']['vlan'] = array();
1101
	echo "\n";
1102

    
1103
	$vlanif = 0;
1104

    
1105
	while (1) {
1106
		$vlan = array();
1107

    
1108
		echo "\n\nVLAN Capable interfaces:\n\n";
1109
		if(!is_array($iflist)) {
1110
			echo "No interfaces found!\n";
1111
		} else {
1112
			$vlan_capable=0;
1113
			foreach ($iflist as $iface => $ifa) {
1114
				if (is_jumbo_capable($iface)) {
1115
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1116
						$ifa['up'] ? "   (up)" : "");
1117
					$vlan_capable++;
1118
				}
1119
			}
1120
		}
1121

    
1122
		if($vlan_capable == 0) {
1123
			echo "No VLAN capable interfaces detected.\n";
1124
			return;
1125
		}
1126

    
1127
		echo "\nEnter the parent interface name for the new VLAN (or nothing if finished): ";
1128
		$vlan['if'] = chop(fgets($fp));
1129

    
1130
		if ($vlan['if']) {
1131
			if (!array_key_exists($vlan['if'], $iflist) or
1132
			    !is_jumbo_capable($vlan['if'])) {
1133
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1134
				continue;
1135
			}
1136
		} else {
1137
			break;
1138
		}
1139

    
1140
		echo "Enter the VLAN tag (1-4094): ";
1141
		$vlan['tag'] = chop(fgets($fp));
1142
		$vlan['vlanif'] = "vlan{$vlan['tag']}";
1143
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1144
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1145
			continue;
1146
		}
1147
		
1148
		$config['vlans']['vlan'][] = $vlan;
1149
		$vlanif++;
1150
	}
1151
}
1152

    
1153
function cleanup_backupcache($revisions = 30, $lock = true) {
1154
	global $g;
1155
	$i = false;
1156
	
1157
	if ($lock)
1158
		$lockkey = lock('config');
1159
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1160
		conf_mount_rw();
1161
		$backups = get_backups();
1162
		$newbaks = array();
1163
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1164
		$baktimes = $backups['versions'];
1165
		$tocache = array();
1166
		unset($backups['versions']);
1167
   		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1168
   			if(filesize($backup) == 0) {
1169
   				unlink($backup);
1170
   				continue;
1171
   			}
1172
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1173
            if(!in_array($tocheck, $baktimes)) {
1174
				$i = true;
1175
				if($g['booting'])
1176
					echo ".";
1177
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1178
				if($newxml == "-1") {
1179
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1180
					unlink($backup);
1181
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1182
					continue;
1183
				}
1184
				if($newxml['revision']['description'] == "")
1185
					$newxml['revision']['description'] = "Unknown";
1186
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1187
			}
1188
    	}
1189
		foreach($backups as $checkbak) {
1190

    
1191
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1192
				$newbaks[] = $checkbak;
1193
			} else {
1194
				$i = true;
1195
				if($g['booting']) print " " . $tocheck . "r";
1196
			}
1197
		}
1198
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1199
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1200
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1201
			foreach($toslice as $sliced)
1202
				$newcache[$sliced] = $tocache[$sliced];
1203
			foreach($tocache as $version => $versioninfo) {
1204
				if(!in_array($version, array_keys($newcache))) {
1205
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1206
					if($g['booting']) print " " . $tocheck . "d";
1207
				}
1208
			}
1209
			$tocache = $newcache;
1210
		}
1211
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1212
        fwrite($bakout, serialize($tocache));
1213
		fclose($bakout);
1214
		conf_mount_ro();
1215
	}
1216
	if($g['booting'] && $i)
1217
		print "done.\n";
1218
	if ($lock)
1219
		unlock($lockkey);
1220
}
1221

    
1222
function get_backups() {
1223
	global $g;
1224
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1225
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1226
		$bakvers = array_keys($confvers);
1227
		$toreturn = array();
1228
		sort($bakvers);
1229
		// 	$bakvers = array_reverse($bakvers);
1230
		foreach(array_reverse($bakvers) as $bakver)
1231
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1232
	} else {
1233
		return false;
1234
	}
1235
	$toreturn['versions'] = $bakvers;
1236
	return $toreturn;
1237
}
1238

    
1239
function backup_config() {
1240
	global $config, $g;
1241

    
1242
	if($g['platform'] == "cdrom")
1243
		return;
1244

    
1245
	conf_mount_rw();
1246

    
1247
	/* Create backup directory if needed */
1248
	safe_mkdir("{$g['cf_conf_path']}/backup");
1249

    
1250
    if($config['revision']['time'] == "") {
1251
            $baktime = 0;
1252
    } else {
1253
            $baktime = $config['revision']['time'];
1254
    }
1255
    if($config['revision']['description'] == "") {
1256
            $bakdesc = "Unknown";
1257
    } else {
1258
            $bakdesc = $config['revision']['description'];
1259
    }
1260
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1261
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1262
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1263
    } else {
1264
            $backupcache = array();
1265
    }
1266
    $backupcache[$baktime] = array('description' => $bakdesc);
1267
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1268
    fwrite($bakout, serialize($backupcache));
1269
    fclose($bakout);
1270

    
1271
	conf_mount_ro();
1272

    
1273
	return true;
1274
}
1275

    
1276
function set_device_perms() {
1277
	$devices = array(
1278
		'pf'	=> array(	'user'	=> 'proxy',
1279
					'group'	=> 'proxy',
1280
					'mode'	=> 0660),
1281
		);
1282

    
1283
	foreach ($devices as $name => $attr) {
1284
		$path = "/dev/$name";
1285
		if (file_exists($path)) {
1286
			chown($path, $attr['user']);
1287
			chgrp($path, $attr['group']);
1288
			chmod($path, $attr['mode']);
1289
		}
1290
	}
1291
}
1292

    
1293
if($g['booting']) echo ".";
1294
$config = parse_config();
1295

    
1296
?>
(9-9/40)