Project

General

Profile

Download (52.9 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
if($g['booting']) echo ".";
42

    
43
/* do not load this file twice. */
44
if($config_inc_loaded == true)
45
	return;
46
else
47
	$config_inc_loaded = true;
48

    
49
/* include globals/utility/XML parser files */
50
require_once("globals.inc");
51
if($g['booting']) echo ".";
52
require_once("util.inc");
53
if($g['booting']) echo ".";
54
require_once("pfsense-utils.inc");
55
if($g['booting']) echo ".";
56
require_once("xmlparse.inc");
57
if($g['booting']) echo ".";
58
require_once("services.inc");
59

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

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

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

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

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

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

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

    
151
					if ($cfgdevice)
152
						break;
153
				}
154
			}
155
		}
156
		if($g['booting']) echo ".";
157
		if (!$cfgdevice) {
158
			$last_backup = discover_last_backup();
159
			if($last_backup) {
160
				log_error("No config.xml found, attempting last known config restore.");
161
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
162
				restore_backup("/cf/conf/backup/{$last_backup}");
163
			} else {
164
				/* no device found, print an error and die */
165
				echo <<<EOD
166

    
167
*******************************************************************************
168
* FATAL ERROR                                                                 *
169
* The device that contains the configuration file (config.xml) could not be   *
170
* found. pfSense cannot continue booting.                                     *
171
*******************************************************************************
172

    
173

    
174
EOD;
175

    
176
				mwexec("/sbin/halt");
177
				exit;
178
			}
179
		}
180

    
181
		/* write device name to a file for rc.firmware */
182
		$fd = fopen("{$g['varetc_path']}/cfdevice", "w");
183
		fwrite($fd, $cfgdevice . "\n");
184
		fclose($fd);
185

    
186
		/* write out an fstab */
187
		$fd = fopen("{$g['etc_path']}/fstab", "w");
188

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

    
192
		fwrite($fd, $fstab);
193
		fclose($fd);
194
	}
195
	if($g['booting']) echo ".";
196
	/* mount all filesystems */
197
	mwexec("/sbin/mount -a");
198
}
199

    
200
/****f* config/parse_config
201
 * NAME
202
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
203
 * INPUTS
204
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
205
 * RESULT
206
 *   $config      - array containing all configuration variables
207
 ******/
208
function parse_config($parse = false) {
209
	global $g;
210
	if(filesize("{$g['conf_path']}/config.xml") == 0) {
211
		$last_backup = discover_last_backup();
212
		if($last_backup) {
213
			log_error("No config.xml found, attempting last known config restore.");
214
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
215
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
216
		} else {
217
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
218
		}
219
	}
220
	if($g['booting']) echo ".";
221
	config_lock();
222
	if(!$parse) {
223
		if(file_exists($g['tmp_path'] . '/config.cache')) {
224
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
225
			if(is_null($config)) {
226
				config_unlock();
227
				parse_config(true);
228
			}
229
		} else {
230
			config_unlock();
231
			if(!file_exists($g['conf_path'] . "/config.xml")) {
232
				log_error("No config.xml found, attempting last known config restore.");
233
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
234
				$last_backup = discover_last_backup();
235
				if ($last_backup)
236
					restore_backup("/cf/conf/backup/{$last_backup}");
237
				else
238
					log_error("Could not restore config.xml.");
239
			}
240
			$config = parse_config(true);
241
		}
242
	} else {
243
		if(!file_exists($g['conf_path'] . "/config.xml")) {
244
			if($g['booting']) echo ".";
245
			log_error("No config.xml found, attempting last known config restore.");
246
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
247
			$last_backup = discover_last_backup();
248
			if ($last_backup)
249
				restore_backup("/cf/conf/backup/{$last_backup}");
250
			else
251
				log_error("Could not restore config.xml.");
252
		}
253
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
254
		if($config == "-1") {
255
			$last_backup = discover_last_backup();
256
			if ($last_backup)
257
				restore_backup("/cf/conf/backup/{$last_backup}");
258
			else
259
				log_error(gettext("Could not restore config.xml."));
260
		}
261
		generate_config_cache($config);
262
	}
263
	if($g['booting']) echo ".";
264
	alias_make_table($config);
265
	config_unlock();
266

    
267
	/*    override some global configuration parms if they exist
268
	 *    instead of hard coding these checks into the codebase
269
     */
270
	if($config['pptp']['n_pptp_units'])
271
		$g['n_pptp_units'] = $config['pptp']['n_pptp_units'];
272
	if($config['pptp']['pptp_subnet'])
273
		$g['pptp_subnet'] = $config['pptp']['pptp_subnet'];
274

    
275
	if($config['pppoe']['n_pppoe_units'])
276
		$g['n_pppoe_units'] = $config['pppoe']['n_pppoe_units'];
277
	if($config['pppoe']['pppoe_subnet'])
278
		$g['pppoe_subnet'] = $config['pppoe']['pppoe_subnet'];
279

    
280
	return $config;
281
}
282

    
283
/****f* config/generate_config_cache
284
 * NAME
285
 *   generate_config_cache - Write serialized configuration to cache.
286
 * INPUTS
287
 *   $config	- array containing current firewall configuration
288
 * RESULT
289
 *   boolean	- true on completion
290
 ******/
291
function generate_config_cache($config) {
292
	global $g;
293
	config_lock();
294
	conf_mount_rw();
295
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
296
	fwrite($configcache, serialize($config));
297
	fclose($configcache);
298
	conf_mount_ro();
299
	config_unlock();
300
	return true;
301
}
302

    
303
function discover_last_backup() {
304
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
305
		$last_backup = "";
306
        foreach($backups as $backup)
307
        	if($backup)
308
	        	$last_backup = $backup;
309
        return $last_backup;
310
}
311

    
312
function restore_backup($file) {
313
	config_lock();
314
	if(file_exists($file)) {
315
		conf_mount_rw();
316
		copy("$file","/cf/conf/config.xml");
317
		unlink_if_exists("/tmp/config.cache");
318
		log_error("pfSense is restoring the configuration $file");
319
		file_notice("config.xml", "pfSense is restoring the configuration $file", "pfSenseConfigurator", "");
320
		conf_mount_ro();
321
	}
322
	config_unlock();
323
}
324

    
325
/****f* config/parse_config_bootup
326
 * NAME
327
 *   parse_config_bootup - Bootup-specific configuration checks.
328
 * RESULT
329
 *   null
330
 ******/
331
function parse_config_bootup() {
332
	global $config, $g, $noparseconfig;
333
	if($g['booting']) echo ".";
334
	if (!$noparseconfig) {
335
		if (!file_exists("{$g['conf_path']}/config.xml")) {
336
			config_lock();
337
			if ($g['booting']) {
338
				if (strstr($g['platform'], "cdrom")) {
339
					/* try copying the default config. to the floppy */
340
					echo "Resetting factory defaults...\n";
341
					reset_factory_defaults();
342
					if (file_exists("{$g['conf_path']}/config.xml")) {
343
						/* do nothing, we have a file. */
344
					} else {
345
						echo "No XML configuration file found - using factory defaults.\n";
346
						echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
347
						echo "file is inserted. If it isn't, your configuration changes will be lost\n";
348
						echo "on reboot.\n";
349
					}
350
				} else {
351
					$last_backup = discover_last_backup();
352
					if($last_backup) {
353
						log_error("No config.xml found, attempting last known config restore.");
354
						file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
355
						restore_backup("/cf/conf/backup/{$last_backup}");
356
					}
357
					if(!file_exists("{$g['conf_path']}/config.xml")) {
358
						echo "XML configuration file not found.  pfSense cannot continue booting.\n";
359
						mwexec("/sbin/halt");
360
						exit;
361
					}
362
					log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
363
				}
364
			} else {
365
				config_unlock();
366
				exit(0);
367
			}
368
		}
369
	}
370
	
371
	if(filesize("{$g['conf_path']}/config.xml") == 0) {
372
		$last_backup = discover_last_backup();
373
		if($last_backup) {
374
			log_error("No config.xml found, attempting last known config restore.");
375
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
376
		} else {
377
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
378
		}
379
	}
380

    
381
	parse_config(true);
382

    
383
	if ((float)$config['version'] > (float)$g['latest_config']) {
384
		echo <<<EOD
385

    
386

    
387
*******************************************************************************
388
* WARNING!                                                                    *
389
* The current configuration has been created with a newer version of pfSense  *
390
* than this one! This can lead to serious misbehavior and even security       *
391
* holes! You are urged to either upgrade to a newer version of pfSense or     *
392
* revert to the default configuration immediately!                            *
393
*******************************************************************************
394

    
395

    
396
EOD;
397
		}
398

    
399
	/* make alias table (for faster lookups) */
400
	alias_make_table($config);
401
	config_unlock();
402
}
403

    
404
/****f* config/conf_mount_rw
405
 * NAME
406
 *   conf_mount_rw - Mount filesystems read/write.
407
 * RESULT
408
 *   null
409
 ******/
410
/* mount flash card read/write */
411
function conf_mount_rw() {
412
	global $g;
413

    
414
	/* do not mount on cdrom platform */
415
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
416
		return;
417
		
418
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
419
	if($status <> 0) {
420
		if($g['booting'])
421
			echo "Disk is dirty.  Running fsck -y\n";
422
		mwexec("/sbin/fsck -y {$g['cf_path']}");
423
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
424
	}
425

    
426
	/*    if the platform is soekris or wrap or pfSense, lets mount the
427
	 *    compact flash cards root.
428
         */
429
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
430
	   or $g['platform'] == "embedded") {
431
		$status = mwexec("/sbin/mount -u -w /");
432
		/* we could not mount this correctly.  kick off fsck */
433
		if($status <> 0) {
434
			log_error("File system is dirty.  Launching FSCK for /");
435
			mwexec("/sbin/fsck -y /");
436
			$status = mwexec("/sbin/mount -u -w /");
437
		}
438
	}
439
}
440

    
441
/****f* config/conf_mount_ro
442
 * NAME
443
 *   conf_mount_ro - Mount filesystems readonly.
444
 * RESULT
445
 *   null
446
 ******/
447
function conf_mount_ro() {
448
	global $g;
449

    
450
	if($g['booting'] == true)
451
		return;
452

    
453
	/* firmare upgrade in progress */
454
	if(file_exists($g['varrun_path'] . "/fwup.enabled"))
455
		return;
456

    
457
	/* do not umount if generating ssh keys */
458
	if(file_exists("/tmp/keys_generating"))
459
		return;
460

    
461
	/* do not umount on cdrom or pfSense platforms */
462
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
463
		return;
464

    
465
	/* sync data, then force a remount of /cf */
466
	mwexec("/bin/sync");
467
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
468
	mwexec("/sbin/mount -u -r -f /");
469
}
470

    
471
/****f* config/convert_config
472
 * NAME
473
 *   convert_config - Attempt to update config.xml.
474
 * DESCRIPTION
475
 *   convert_config() reads the current global configuration
476
 *   and attempts to convert it to conform to the latest
477
 *   config.xml version. This allows major formatting changes
478
 *   to be made with a minimum of breakage.
479
 * RESULT
480
 *   null
481
 ******/
482
/* convert configuration, if necessary */
483
function convert_config() {
484
	global $config, $g;
485

    
486
	/* special case upgrades */
487
	/* fix every minute crontab bogons entry */
488
	$cron_item_count = count($config['cron']['item']);
489
	for($x=0; $x<$cron_item_count; $x++) {
490
		if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
491
			if($config['cron']['item'][$x]['hour'] == "*" ) {
492
		        $config['cron']['item'][$x]['hour'] = "3";
493
		 		write_config("Updated bogon update frequency to 3am");
494
		 		log_error("Updated bogon update frequency to 3am");
495
		 	}       
496
		}
497
	}
498

    
499
	if ($config['version'] == $g['latest_config'])
500
		return;		/* already at latest version */
501

    
502
	// Save off config version
503
	$prev_version = $config['version'];
504

    
505
	/* convert 1.0 -> 1.1 */
506
	if ($config['version'] <= 1.0) {
507
		$opti = 1;
508
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
509

    
510
		/* convert DMZ to optional, if necessary */
511
		if (isset($config['interfaces']['dmz'])) {
512

    
513
			$dmzcfg = &$config['interfaces']['dmz'];
514

    
515
			if ($dmzcfg['if']) {
516
				$config['interfaces']['opt' . $opti] = array();
517
				$optcfg = &$config['interfaces']['opt' . $opti];
518

    
519
				$optcfg['enable'] = $dmzcfg['enable'];
520
				$optcfg['descr'] = "DMZ";
521
				$optcfg['if'] = $dmzcfg['if'];
522
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
523
				$optcfg['subnet'] = $dmzcfg['subnet'];
524

    
525
				$ifmap['dmz'] = "opt" . $opti;
526
				$opti++;
527
			}
528

    
529
			unset($config['interfaces']['dmz']);
530
		}
531

    
532
		/* convert WLAN1/2 to optional, if necessary */
533
		for ($i = 1; isset($config['interfaces']['wlan' . $i]); $i++) {
534

    
535
			if (!$config['interfaces']['wlan' . $i]['if']) {
536
				unset($config['interfaces']['wlan' . $i]);
537
				continue;
538
			}
539

    
540
			$wlancfg = &$config['interfaces']['wlan' . $i];
541
			$config['interfaces']['opt' . $opti] = array();
542
			$optcfg = &$config['interfaces']['opt' . $opti];
543

    
544
			$optcfg['enable'] = $wlancfg['enable'];
545
			$optcfg['descr'] = "WLAN" . $i;
546
			$optcfg['if'] = $wlancfg['if'];
547
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
548
			$optcfg['subnet'] = $wlancfg['subnet'];
549
			$optcfg['bridge'] = $wlancfg['bridge'];
550

    
551
			$optcfg['wireless'] = array();
552
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
553
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
554
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
555
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
556

    
557
			$ifmap['wlan' . $i] = "opt" . $opti;
558

    
559
			unset($config['interfaces']['wlan' . $i]);
560
			$opti++;
561
		}
562

    
563
		/* convert filter rules */
564
		$n = count($config['filter']['rule']);
565
		for ($i = 0; $i < $n; $i++) {
566

    
567
			$fr = &$config['filter']['rule'][$i];
568

    
569
			/* remap interface */
570
			if (array_key_exists($fr['interface'], $ifmap))
571
				$fr['interface'] = $ifmap[$fr['interface']];
572
			else {
573
				/* remove the rule */
574
				echo "\nWarning: filter rule removed " .
575
					"(interface '{$fr['interface']}' does not exist anymore).";
576
				unset($config['filter']['rule'][$i]);
577
				continue;
578
			}
579

    
580
			/* remap source network */
581
			if (isset($fr['source']['network'])) {
582
				if (array_key_exists($fr['source']['network'], $ifmap))
583
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
584
				else {
585
					/* remove the rule */
586
					echo "\nWarning: filter rule removed " .
587
						"(source network '{$fr['source']['network']}' does not exist anymore).";
588
					unset($config['filter']['rule'][$i]);
589
					continue;
590
				}
591
			}
592

    
593
			/* remap destination network */
594
			if (isset($fr['destination']['network'])) {
595
				if (array_key_exists($fr['destination']['network'], $ifmap))
596
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
597
				else {
598
					/* remove the rule */
599
					echo "\nWarning: filter rule removed " .
600
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
601
					unset($config['filter']['rule'][$i]);
602
					continue;
603
				}
604
			}
605
		}
606

    
607
		/* convert shaper rules */
608
		$n = count($config['pfqueueing']['rule']);
609
		if (is_array($config['pfqueueing']['rule']))
610
			for ($i = 0; $i < $n; $i++) {
611

    
612
			$fr = &$config['pfqueueing']['rule'][$i];
613

    
614
			/* remap interface */
615
			if (array_key_exists($fr['interface'], $ifmap))
616
				$fr['interface'] = $ifmap[$fr['interface']];
617
			else {
618
				/* remove the rule */
619
				echo "\nWarning: traffic shaper rule removed " .
620
					"(interface '{$fr['interface']}' does not exist anymore).";
621
				unset($config['pfqueueing']['rule'][$i]);
622
				continue;
623
			}
624

    
625
			/* remap source network */
626
			if (isset($fr['source']['network'])) {
627
				if (array_key_exists($fr['source']['network'], $ifmap))
628
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
629
				else {
630
					/* remove the rule */
631
					echo "\nWarning: traffic shaper rule removed " .
632
						"(source network '{$fr['source']['network']}' does not exist anymore).";
633
					unset($config['pfqueueing']['rule'][$i]);
634
					continue;
635
				}
636
			}
637

    
638
			/* remap destination network */
639
			if (isset($fr['destination']['network'])) {
640
				if (array_key_exists($fr['destination']['network'], $ifmap))
641
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
642
				else {
643
					/* remove the rule */
644
					echo "\nWarning: traffic shaper rule removed " .
645
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
646
					unset($config['pfqueueing']['rule'][$i]);
647
					continue;
648
				}
649
			}
650
		}
651

    
652
		$config['version'] = "1.1";
653
	}
654

    
655
	/* convert 1.1 -> 1.2 */
656
	if ($config['version'] <= 1.1) {
657
		/* move LAN DHCP server config */
658
		$tmp = $config['dhcpd'];
659
		$config['dhcpd'] = array();
660
		$config['dhcpd']['lan'] = $tmp;
661

    
662
		/* encrypt password */
663
		$config['system']['password'] = crypt($config['system']['password']);
664

    
665
		$config['version'] = "1.2";
666
	}
667

    
668
	/* convert 1.2 -> 1.3 */
669
	if ($config['version'] <= 1.2) {
670
		/* convert advanced outbound NAT config */
671
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
672
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
673
			$src = $curent['source'];
674
			$curent['source'] = array();
675
			$curent['source']['network'] = $src;
676
			$curent['destination'] = array();
677
			$curent['destination']['any'] = true;
678
		}
679

    
680
		/* add an explicit type="pass" to all filter rules to make things consistent */
681
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
682
			$config['filter']['rule'][$i]['type'] = "pass";
683
		}
684

    
685
		$config['version'] = "1.3";
686
	}
687

    
688
	/* convert 1.3 -> 1.4 */
689
	if ($config['version'] <= 1.3) {
690
		/* convert shaper rules (make pipes) */
691
		if (is_array($config['pfqueueing']['rule'])) {
692
			$config['pfqueueing']['pipe'] = array();
693

    
694
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
695
				$curent = &$config['pfqueueing']['rule'][$i];
696

    
697
				/* make new pipe and associate with this rule */
698
				$newpipe = array();
699
				$newpipe['descr'] = $curent['descr'];
700
				$newpipe['bandwidth'] = $curent['bandwidth'];
701
				$newpipe['delay'] = $curent['delay'];
702
				$newpipe['mask'] = $curent['mask'];
703
				$config['pfqueueing']['pipe'][$i] = $newpipe;
704

    
705
				$curent['targetpipe'] = $i;
706

    
707
				unset($curent['bandwidth']);
708
				unset($curent['delay']);
709
				unset($curent['mask']);
710
			}
711
		}
712

    
713
		$config['version'] = "1.4";
714
	}
715

    
716
	/* Convert 1.4 -> 1.5 */
717
	if ($config['version'] <= 1.4) {
718

    
719
		/* Default route moved */
720
		if (isset($config['interfaces']['wan']['gateway']))
721
			if ($config['interfaces']['wan']['gateway'] <> "")
722
				$config['interfaces']['wan']['gateway'] = $config['interfaces']['wan']['gateway'];
723
		unset($config['interfaces']['wan']['gateway']);
724

    
725
                /* Queues are no longer interface specific */
726
                if (isset($config['interfaces']['lan']['schedulertype']))
727
                        unset($config['interfaces']['lan']['schedulertype']);
728
                if (isset($config['interfaces']['wan']['schedulertype']))
729
                        unset($config['interfaces']['wan']['schedulertype']);
730

    
731
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
732
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
733
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
734
                }
735

    
736
		$config['version'] = "1.5";
737
	}
738

    
739
	/* Convert 1.5 -> 1.6 */
740
	if ($config['version'] <= 1.5) {
741
		/* Alternate firmware URL moved */
742
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
743
			$config['system']['alt_firmware_url'] = array();
744
			$config['system']['alt_firmware_url']['enabled'] = "";
745
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
746
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
747
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
748
		} else {
749
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
750
		}
751

    
752
		$config['version'] = "1.6";
753
	}
754

    
755
	/* Convert 1.6 -> 1.7 */
756
	if ($config['version'] <= 1.6) {
757
		/* wipe previous shaper configuration */
758
		unset($config['shaper']['queue']);
759
		unset($config['shaper']['rule']);
760
		unset($config['interfaces']['wan']['bandwidth']);
761
		unset($config['interfaces']['wan']['bandwidthtype']);
762
		unset($config['interfaces']['lan']['bandwidth']);
763
		unset($config['interfaces']['lan']['bandwidthtype']);
764
		$config['shaper']['enable'] = FALSE;
765
		$config['version'] = "1.7";
766
	}
767
	/* Convert 1.7 -> 1.8 */
768
	if ($config['version'] <= 1.7) {
769
		if(isset($config['proxyarp']) && is_array($config['proxyarp']['proxyarpnet'])) {
770
			$proxyarp = &$config['proxyarp']['proxyarpnet'];
771
			foreach($proxyarp as $arpent){
772
				$vip = array();
773
				$vip['mode'] = "proxyarp";
774
				$vip['interface'] = $arpent['interface'];
775
				$vip['descr'] = $arpent['descr'];
776
				if (isset($arpent['range'])) {
777
					$vip['range'] = $arpent['range'];
778
					$vip['type'] = "range";
779
				} else {
780
					$subnet = explode('/', $arpent['network']);
781
					$vip['subnet'] = $subnet[0];
782
					if (isset($subnet[1])) {
783
						$vip['subnet_bits'] = $subnet[1];
784
						$vip['type'] = "network";
785
					} else {
786
						$vip['subnet_bits'] = "32";
787
						$vip['type'] = "single";
788
					}
789
				}
790
				$config['virtualip']['vip'][] = $vip;
791
			}
792
			unset($config['proxyarp']);
793
		}
794
		if(isset($config['installedpackages']) && isset($config['installedpackages']['carp']) && is_array($config['installedpackages']['carp']['config'])) {
795
			$carp = &$config['installedpackages']['carp']['config'];
796
			foreach($carp as $carpent){
797
				$vip = array();
798
				$vip['mode'] = "carp";
799
				$vip['interface'] = "AUTO";
800
				$vip['descr'] = "CARP vhid {$carpent['vhid']}";
801
				$vip['type'] = "single";
802
				$vip['vhid'] = $carpent['vhid'];
803
				$vip['advskew'] = $carpent['advskew'];
804
				$vip['password'] = $carpent['password'];
805
				$vip['subnet'] = $carpent['ipaddress'];
806
				$vip['subnet_bits'] = $carpent['netmask'];
807
				$config['virtualip']['vip'][] = $vip;
808
			}
809
			unset($config['installedpackages']['carp']);
810
		}
811
		/* Server NAT is no longer needed */
812
		unset($config['nat']['servernat']);
813

    
814
		/* enable SSH */
815
		if ($config['version'] == "1.8") {
816
			$config['system']['sshenabled'] = true;
817
		}
818

    
819
		$config['version'] = "1.9";
820
	}
821

    
822
	/* Convert 1.8 -> 1.9 */
823
	if ($config['version'] <= 1.8) {
824
		$config['theme']="metallic";
825
		$config['version'] = "1.9";
826
	}
827
	/* Convert 1.9 -> 2.0 */
828
	if ($config['version'] <= 1.9) {
829
		if(is_array($config['ipsec']['tunnel'])) {
830
			reset($config['ipsec']['tunnel']);
831
			while (list($index, $tunnel) = each($config['ipsec']['tunnel'])) {
832
				/* Sanity check on required variables */
833
				/* This fixes bogus <tunnel> entries - remnant of bug #393 */
834
				if (!isset($tunnel['local-subnet']) && !isset($tunnel['remote-subnet'])) {
835
					unset($config['ipsec']['tunnel'][$tunnel]);
836
				}
837
			}
838
        	}
839
		$config['version'] = "2.0";
840
	}
841
	/* Convert 2.0 -> 2.1 */
842
	if ($config['version'] <= 2.0) {
843
		/* shaper scheduler moved */
844
		if(isset($config['system']['schedulertype'])) {
845
			$config['shaper']['schedulertype'] = $config['system']['schedulertype'];
846
			unset($config['system']['schedulertype']);
847
		}
848
		$config['version'] = "2.1";
849
	}
850
	/* Convert 2.1 -> 2.2 */
851
	if ($config['version'] <= 2.1) {
852
		/* move gateway to wan interface */
853
		$config['interfaces']['wan']['gateway'] = $config['system']['gateway'];
854
		$config['version'] = "2.2";
855
	}
856
	/* Convert 2.2 -> 2.3 */
857
	if ($config['version'] <= 2.2) {
858
		if(isset($config['shaper'])) {
859
			/* wipe previous shaper configuration */
860
			unset($config['shaper']);
861
		}
862
		$config['version'] = "2.3";
863
	}
864

    
865
	/* Convert 2.4 -> 2.5 */
866
	if ($config['version'] <= 2.4) {
867
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
868
		unset($config['system']['use_rrd_gateway']);
869
 		$config['version'] = "2.5";
870
	}
871

    
872
	/* Convert 2.5 -> 2.6 */
873
	if ($config['version'] <= 2.5) {
874
		$cron_item = array();
875
		$cron_item['minute'] = "0";
876
		$cron_item['hour'] = "*";
877
		$cron_item['mday'] = "*";
878
		$cron_item['month'] = "*";
879
		$cron_item['wday'] = "*";
880
		$cron_item['who'] = "root";
881
		$cron_item['command'] = "/usr/bin/nice -n20 newsyslog";
882

    
883
		$config['cron']['item'][] = $cron_item;
884

    
885
		$cron_item = array();
886
		$cron_item['minute'] = "1,31";
887
		$cron_item['hour'] = "0-5";
888
		$cron_item['mday'] = "*";
889
		$cron_item['month'] = "*";
890
		$cron_item['wday'] = "*";
891
		$cron_item['who'] = "root";
892
		$cron_item['command'] = "/usr/bin/nice -n20 adjkerntz -a";
893

    
894
		$config['cron']['item'][] = $cron_item;
895

    
896
		$cron_item = array();
897
		$cron_item['minute'] = "1";
898
		$cron_item['hour'] = "*";
899
		$cron_item['mday'] = "1";
900
		$cron_item['month'] = "*";
901
		$cron_item['wday'] = "*";
902
		$cron_item['who'] = "root";
903
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.update_bogons.sh";
904

    
905
		$config['cron']['item'][] = $cron_item;
906

    
907
		$cron_item = array();
908
		$cron_item['minute'] = "*/60";
909
		$cron_item['hour'] = "*";
910
		$cron_item['mday'] = "*";
911
		$cron_item['month'] = "*";
912
		$cron_item['wday'] = "*";
913
		$cron_item['who'] = "root";
914
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 sshlockout";
915

    
916
		$config['cron']['item'][] = $cron_item;
917

    
918
		$cron_item = array();
919
		$cron_item['minute'] = "1";
920
		$cron_item['hour'] = "1";
921
		$cron_item['mday'] = "*";
922
		$cron_item['month'] = "*";
923
		$cron_item['wday'] = "*";
924
		$cron_item['who'] = "root";
925
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.dyndns.update";
926

    
927
		$config['cron']['item'][] = $cron_item;
928

    
929
		$cron_item = array();
930
		$cron_item['minute'] = "*/60";
931
		$cron_item['hour'] = "*";
932
		$cron_item['mday'] = "*";
933
		$cron_item['month'] = "*";
934
		$cron_item['wday'] = "*";
935
		$cron_item['who'] = "root";
936
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 virusprot";
937

    
938
		$config['cron']['item'][] = $cron_item;
939

    
940
		$cron_item = array();
941
		$cron_item['minute'] = "*/60";
942
		$cron_item['hour'] = "*";
943
		$cron_item['mday'] = "*";
944
		$cron_item['month'] = "*";
945
		$cron_item['wday'] = "*";
946
		$cron_item['who'] = "root";
947
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -t 1800 snort2c";
948

    
949
		$config['cron']['item'][] = $cron_item;
950

    
951
		$cron_item = array();
952
		$cron_item['minute'] = "*/5";
953
		$cron_item['hour'] = "*";
954
		$cron_item['mday'] = "*";
955
		$cron_item['month'] = "*";
956
		$cron_item['wday'] = "*";
957
		$cron_item['who'] = "root";
958
		$cron_item['command'] = "/usr/local/bin/checkreload.sh";
959

    
960
		$config['cron']['item'][] = $cron_item;
961

    
962
		/* write crontab entries to file */
963
		configure_cron();
964

    
965
 		$config['version'] = "2.6";
966
	}
967

    
968
	/* Convert 2.6 -> 2.7 */
969
	if ($config['version'] <= 2.6) {
970
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
971
		unset($config['system']['use_rrd_gateway']);
972
		$config['version'] = "2.7";
973
	}
974

    
975
	/* Convert 2.7 -> 2.8 */
976
	if ($config['version'] <= 2.7) {
977
		$founditem = false;
978
		foreach($config['cron']['item'] as $cronitem) {
979
			if($cronitem['command'] == "/usr/local/bin/checkreload.sh")
980
				$founditem = true;
981
		}
982
		if($founditem == false) {
983
			$cron_item = array();
984
			$cron_item['minute'] = "*/5";
985
			$cron_item['hour'] = "*";
986
			$cron_item['mday'] = "*";
987
			$cron_item['month'] = "*";
988
			$cron_item['wday'] = "*";
989
			$cron_item['who'] = "root";
990
			$cron_item['command'] = "/usr/local/bin/checkreload.sh";
991
			$config['cron']['item'][] = $cron_item;
992
		}
993
		$config['version'] = "2.8";
994
	}
995

    
996
	/* Convert 2.8 -> 2.9 */
997
	if ($config['version'] <= 2.8) {
998
		$rule_item = array();
999
		$a_filter = &$config['filter']['rule'];
1000
		$rule_item['interface'] = "enc0";
1001
		$rule_item['type'] = "pass";
1002
		$rule_item['source']['any'] = true;
1003
		$rule_item['destination']['any'] = true;
1004
		$rule_item['descr'] = "Permit IPSEC traffic.";
1005
		$rule_item['statetype'] = "keep state";
1006
		$a_filter[] = $rule_item;
1007
		$config['version'] = "2.9";
1008
	}
1009

    
1010
	/* Convert 2.9 -> 3.0 */
1011
	if ($config['version'] <= 2.9) {
1012
		/* enable the rrd config setting by default */
1013
		$config['rrd']['enable'] = true;
1014
		$config['version'] = "3.0";
1015
 	}
1016

    
1017
	if ($prev_version != $config['version'])
1018
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
1019
}
1020

    
1021
/****f* config/write_config
1022
 * NAME
1023
 *   write_config - Backup and write the firewall configuration.
1024
 * DESCRIPTION
1025
 *   write_config() handles backing up the current configuration,
1026
 *   applying changes, and regenerating the configuration cache.
1027
 * INPUTS
1028
 *   $desc	- string containing the a description of configuration changes
1029
 *   $backup	- boolean: do not back up current configuration if false.
1030
 * RESULT
1031
 *   null
1032
 ******/
1033
/* save the system configuration */
1034
function write_config($desc="Unknown", $backup = true) {
1035
	global $config, $g;
1036

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

    
1040
	if($backup)
1041
		backup_config();
1042

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

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

    
1050
	$config['revision']['description'] = $desc;
1051
	$config['revision']['time'] = $changetime;
1052

    
1053
	config_lock();
1054

    
1055
	/* generate configuration XML */
1056
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
1057

    
1058
	conf_mount_rw();
1059

    
1060
	/* write new configuration */
1061
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
1062
	if (!$fd)
1063
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
1064
	fwrite($fd, $xmlconfig);
1065
	fclose($fd);
1066

    
1067
	if($g['platform'] == "embedded") {
1068
		cleanup_backupcache(5);
1069
	} else {
1070
		cleanup_backupcache(30);
1071
	}
1072

    
1073
	if($g['booting'] <> true) {
1074
		conf_mount_ro();
1075
	}
1076

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

    
1080
	/* write config cache */
1081
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
1082
	if ($fd) {
1083
		fwrite($fd, serialize($config));
1084
		fclose($fd);
1085
	}
1086

    
1087
	/* tell kernel to sync fs data */
1088
	mwexec("/bin/sync");
1089

    
1090
	config_unlock();
1091

    
1092
	return $config;
1093
}
1094

    
1095
/****f* config/reset_factory_defaults
1096
 * NAME
1097
 *   reset_factory_defaults - Reset the system to its default configuration.
1098
 * RESULT
1099
 *   integer	- indicates completion
1100
 ******/
1101
function reset_factory_defaults() {
1102
	global $g;
1103

    
1104
	config_lock();
1105
	conf_mount_rw();
1106

    
1107
	/* create conf directory, if necessary */
1108
	safe_mkdir("{$g['cf_conf_path']}");
1109

    
1110
	/* clear out /conf */
1111
	$dh = opendir($g['conf_path']);
1112
	while ($filename = readdir($dh)) {
1113
		if (($filename != ".") && ($filename != "..")) {
1114
			unlink_if_exists($g['conf_path'] . "/" . $filename);
1115
		}
1116
	}
1117
	closedir($dh);
1118

    
1119
	/* copy default configuration */
1120
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
1121

    
1122
	/* call the wizard */
1123
	touch("/conf/trigger_initial_wizard");
1124

    
1125
	conf_mount_ro();
1126
	config_unlock();
1127

    
1128
	return 0;
1129
}
1130

    
1131
function config_restore($conffile) {
1132
	global $config, $g;
1133

    
1134
	if (!file_exists($conffile))
1135
		return 1;
1136

    
1137
    config_lock();
1138
    conf_mount_rw();
1139

    
1140
    backup_config();
1141
    copy($conffile, "{$g['cf_conf_path']}/config.xml");
1142
	$config = parse_config(true);
1143
    write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
1144

    
1145
    conf_mount_ro();
1146
    config_unlock();
1147

    
1148
    return 0;
1149
}
1150

    
1151
function config_install($conffile) {
1152
	global $config, $g;
1153

    
1154
	if (!file_exists($conffile))
1155
		return 1;
1156

    
1157
	if (!config_validate("{$g['conf_path']}/config.xml"))
1158
		return 1;
1159

    
1160
	if($g['booting'] == true)
1161
		echo "Installing configuration...\n";
1162

    
1163
    config_lock();
1164
    conf_mount_rw();
1165

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

    
1168
	/* unlink cache file if it exists */
1169
	if(file_exists("{$g['tmp_path']}/config.cache"))
1170
		unlink("{$g['tmp_path']}/config.cache");
1171

    
1172
    conf_mount_ro();
1173
    config_unlock();
1174

    
1175
    return 0;
1176
}
1177

    
1178
function config_validate($conffile) {
1179

    
1180
	global $g, $xmlerr;
1181

    
1182
	$xml_parser = xml_parser_create();
1183

    
1184
	if (!($fp = fopen($conffile, "r"))) {
1185
		$xmlerr = "XML error: unable to open file";
1186
		return false;
1187
	}
1188

    
1189
	while ($data = fread($fp, 4096)) {
1190
		if (!xml_parse($xml_parser, $data, feof($fp))) {
1191
			$xmlerr = sprintf("%s at line %d",
1192
						xml_error_string(xml_get_error_code($xml_parser)),
1193
						xml_get_current_line_number($xml_parser));
1194
			return false;
1195
		}
1196
	}
1197
	xml_parser_free($xml_parser);
1198

    
1199
	fclose($fp);
1200

    
1201
	return true;
1202
}
1203

    
1204
/*   lock configuration file, decide that the lock file
1205
 *   is stale after 10 seconds
1206
 */
1207
function config_lock() {
1208
	global $g, $process_lock;
1209

    
1210
	/* No need to continue if we're the ones holding the lock */
1211
	if ($process_lock)
1212
		return;
1213

    
1214
	$lockfile = "{$g['varrun_path']}/config.lock";
1215

    
1216
	$n = 0;
1217
	while ($n < 10) {
1218
		/* open the lock file in append mode to avoid race condition */
1219
		if ($fd = @fopen($lockfile, "x")) {
1220
			/* succeeded */
1221
			$process_lock = true;
1222
			fclose($fd);
1223
			return;
1224
		} else {
1225
			/* file locked, wait and try again */
1226
			if($n == 4) 
1227
				log_error("[DEBUG] Lock recursion detected.");
1228
			$process_lock = false;
1229
			sleep(1);
1230
			$n++;
1231
		}
1232
	}
1233
}
1234

    
1235
/* unlock configuration file */
1236
function config_unlock() {
1237
	global $g, $process_lock;
1238

    
1239
	$lockfile = "{$g['varrun_path']}/config.lock";
1240
	$process_lock = false;
1241

    
1242
	unlink_if_exists($lockfile);
1243
}
1244

    
1245
function set_networking_interfaces_ports() {
1246
	global $noreboot;
1247
	global $config;
1248
	global $g;
1249
	global $fp;
1250

    
1251
	$fp = fopen('php://stdin', 'r');
1252

    
1253
	$memory = get_memory();
1254
	$avail = $memory[0];
1255

    
1256
	if($avail < 115) {
1257
		echo "\n\n\n";
1258
		echo "DANGER!  WARNING!\n\n";
1259
		echo "pfSense requires *AT LEAST* 128 megs of ram to function correctly.\n";
1260
		echo "Only ($avail) megs of ram has been detected.\n";
1261
		echo "\nPress ENTER to continue.";
1262
		fgets($fp);
1263
		echo "\n";
1264
	}
1265

    
1266
	$iflist = get_interface_list();
1267

    
1268
	echo <<<EOD
1269

    
1270
Valid interfaces are:
1271

    
1272

    
1273
EOD;
1274

    
1275
	if(!is_array($iflist)) {
1276
		echo "No interfaces found!\n";
1277
	} else {
1278
		foreach ($iflist as $iface => $ifa) {
1279
			echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1280
				$ifa['up'] ? "   (up)" : "");
1281
		}
1282
	}
1283

    
1284
	echo <<<EOD
1285

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

    
1290
Do you want to set up VLANs now [y|n]?
1291
EOD;
1292

    
1293
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
1294
		vlan_setup();
1295

    
1296
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1297

    
1298
		echo "\n\nVLAN interfaces:\n\n";
1299
		$i = 0;
1300
		foreach ($config['vlans']['vlan'] as $vlan) {
1301

    
1302
			echo sprintf("% -8s%s\n", "vlan{$i}",
1303
				"VLAN tag {$vlan['tag']}, interface {$vlan['if']}");
1304

    
1305
			$iflist['vlan' . $i] = array();
1306
			$i++;
1307
		}
1308
	}
1309

    
1310
	echo <<<EOD
1311

    
1312
*NOTE*  pfSense requires *AT LEAST* 2 assigned interfaces to function.
1313
        If you do not have two interfaces you CANNOT continue. 
1314

    
1315
        If you do not have at least two *REAL* network interface cards
1316
        or one interface with multiple VLANs then pfSense *WILL NOT*
1317
        function correctly.
1318

    
1319
If you do not know the names of your interfaces, you may choose to use
1320
auto-detection. In that case, disconnect all interfaces now before
1321
hitting 'a' to initiate auto detection. 
1322

    
1323
EOD;
1324

    
1325
	do {
1326
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
1327
		$lanif = chop(fgets($fp));
1328
		if ($lanif === "") {
1329
			fclose($fp);
1330
			return;
1331
		}
1332

    
1333
		if($lanif == "exit") {
1334
			exit;
1335
		}
1336

    
1337
		if ($lanif === "a")
1338
			$lanif = autodetect_interface("LAN", $fp);
1339
		else if (!array_key_exists($lanif, $iflist)) {
1340
			echo "\nInvalid interface name '{$lanif}'\n";
1341
			unset($lanif);
1342
			continue;
1343
		}
1344
	} while (!$lanif);
1345

    
1346
	do {
1347
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
1348
		$wanif = chop(fgets($fp));
1349
		if ($wanif === "") {
1350
			return;
1351
		}
1352
		if ($wanif === "a")
1353
			$wanif = autodetect_interface("WAN", $fp);
1354
		else if (!array_key_exists($wanif, $iflist)) {
1355
			echo "\nInvalid interface name '{$wanif}'\n";
1356
			unset($wanif);
1357
			continue;
1358
		}
1359
	} while (!$wanif);
1360

    
1361
	/* optional interfaces */
1362
	$i = 0;
1363
	$optif = array();
1364

    
1365
	while (1) {
1366
		if ($optif[$i])
1367
			$i++;
1368
		$i1 = $i + 1;
1369

    
1370
		if($config['interfaces']['opt' . $i1]['descr'])
1371
			echo "\nOptional interface {$i1} description found: {$config['interfaces']['opt' . $i1]['descr']}";
1372

    
1373
		echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
1374
			"(or nothing if finished): ";
1375

    
1376
		$optif[$i] = chop(fgets($fp));
1377

    
1378
		if ($optif[$i]) {
1379
			if ($optif[$i] === "a") {
1380
				$ad = autodetect_interface("Optional " . $i1, $fp);
1381
				if ($ad)
1382
					$optif[$i] = $ad;
1383
				else
1384
					unset($optif[$i]);
1385
			} else if (!array_key_exists($optif[$i], $iflist)) {
1386
				echo "\nInvalid interface name '{$optif[$i]}'\n";
1387
				unset($optif[$i]);
1388
				continue;
1389
			}
1390
		} else {
1391
			unset($optif[$i]);
1392
			break;
1393
		}
1394
	}
1395

    
1396
	/* check for double assignments */
1397
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1398

    
1399
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1400
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1401
			if ($ifarr[$i] == $ifarr[$j]) {
1402
				echo <<<EOD
1403

    
1404
Error: you cannot assign the same interface name twice!
1405

    
1406
EOD;
1407
				fclose($fp);
1408
				return;
1409
			}
1410
		}
1411
	}
1412

    
1413
	echo <<<EOD
1414

    
1415
The interfaces will be assigned as follows:
1416

    
1417
LAN  -> {$lanif}
1418
WAN  -> {$wanif}
1419

    
1420
EOD;
1421

    
1422
	for ($i = 0; $i < count($optif); $i++) {
1423
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1424
	}
1425

    
1426
echo <<<EOD
1427

    
1428
Do you want to proceed [y|n]?
1429
EOD;
1430

    
1431
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1432

    
1433
		$config['interfaces']['lan']['if'] = $lanif;
1434
		if (preg_match($g['wireless_regex'], $lanif)) {
1435
			if (!is_array($config['interfaces']['lan']['wireless']))
1436
				$config['interfaces']['lan']['wireless'] = array();
1437
		} else {
1438
			unset($config['interfaces']['lan']['wireless']);
1439
		}
1440

    
1441
		$config['interfaces']['wan']['if'] = $wanif;
1442
		if (preg_match($g['wireless_regex'], $wanif)) {
1443
			if (!is_array($config['interfaces']['wan']['wireless']))
1444
				$config['interfaces']['wan']['wireless'] = array();
1445
		} else {
1446
			unset($config['interfaces']['wan']['wireless']);
1447
		}
1448

    
1449
		for ($i = 0; $i < count($optif); $i++) {
1450
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1451
				$config['interfaces']['opt' . ($i+1)] = array();
1452

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

    
1455
			/* wireless interface? */
1456
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1457
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1458
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1459
			} else {
1460
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1461
			}
1462

    
1463
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1464
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1465
		}
1466

    
1467
		/* remove all other (old) optional interfaces */
1468
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1469
			unset($config['interfaces']['opt' . ($i+1)]);
1470

    
1471
		write_config();
1472

    
1473
		echo <<<EOD
1474

    
1475

    
1476

    
1477
EOD;
1478

    
1479
		fclose($fp);
1480
		
1481
		if($g['booting'])
1482
			return;
1483

    
1484
		echo "One moment while we reload the settings...";
1485

    
1486
		$g['booting'] = false;
1487

    
1488
		/* resync everything */
1489
		reload_all_sync();
1490

    
1491
		echo " done!\n";
1492

    
1493
		touch("{$g['tmp_path']}/assign_complete");
1494

    
1495
	}
1496
}
1497

    
1498
function autodetect_interface($ifname, $fp) {
1499
	$iflist_prev = get_interface_list("media");
1500
	echo <<<EOD
1501

    
1502
Connect the {$ifname} interface now and make sure that the link is up.
1503
Then press ENTER to continue.
1504

    
1505
EOD;
1506
	fgets($fp);
1507
	$iflist = get_interface_list("media");
1508

    
1509
	foreach ($iflist_prev as $ifn => $ifa) {
1510
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1511
			echo "Detected link-up on interface {$ifn}.\n";
1512
			return $ifn;
1513
		}
1514
	}
1515

    
1516
	echo "No link-up detected.\n";
1517

    
1518
	return null;
1519
}
1520

    
1521
function vlan_setup() {
1522
	global $iflist, $config, $g, $fp;
1523

    
1524
	$iflist = get_interface_list();
1525

    
1526
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1527

    
1528
	echo <<<EOD
1529

    
1530
WARNING: all existing VLANs will be cleared if you proceed!
1531

    
1532
Do you want to proceed [y|n]?
1533
EOD;
1534

    
1535
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1536
		return;
1537
	}
1538

    
1539
	$config['vlans']['vlan'] = array();
1540
	echo "\n";
1541

    
1542
	while (1) {
1543
		$vlan = array();
1544

    
1545
		echo "\n\nVLAN Capable interfaces:\n\n";
1546
		if(!is_array($iflist)) {
1547
			echo "No interfaces found!\n";
1548
		} else {
1549
			$vlan_capable=0;
1550
			foreach ($iflist as $iface => $ifa) {
1551
				if (is_jumbo_capable($iface)) {
1552
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1553
						$ifa['up'] ? "   (up)" : "");
1554
					$vlan_capable++;
1555
				}
1556
			}
1557
		}
1558

    
1559
		if($vlan_capable == 0) {
1560
			echo "No VLAN capable interfaces detected.\n";
1561
			return;
1562
		}
1563

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

    
1567
		if ($vlan['if']) {
1568
			if (!array_key_exists($vlan['if'], $iflist) or
1569
			    !is_jumbo_capable($vlan['if'])) {
1570
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1571
				continue;
1572
			}
1573
		} else {
1574
			break;
1575
		}
1576

    
1577
		echo "Enter the VLAN tag (1-4094): ";
1578
		$vlan['tag'] = chop(fgets($fp));
1579

    
1580
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1581
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1582
			continue;
1583
		}
1584

    
1585
		$config['vlans']['vlan'][] = $vlan;
1586
	}
1587
}
1588

    
1589
function system_start_ftp_helpers() {
1590
	require_once("interfaces.inc");
1591
	global $config, $g;
1592

    
1593
	mwexec("/usr/bin/killall ftpsesame");
1594

    
1595
	/* build an array of interfaces to work with */
1596
	$iflist = array("lan" => "lan");
1597
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
1598
		$iflist['opt' . $i] = "opt{$i}";
1599

    
1600
	/* loop through all interfaces and handle pftpx */
1601
	$interface_counter = 0;
1602
	if(isset($config['shaper']['enable'])) {
1603
		if(isset($config['ezshaper']['step5']['p2pcatchall'])) {
1604
			$shaper_queue = "-q qP2PDown ";
1605
		} else { 
1606
			$downq = "q" . convert_friendly_interface_to_friendly_descr($config['ezshaper']['step2']['inside_int']);
1607
			$shaper_queue = "-q {$downq}def ";
1608
		}
1609
	} else {
1610
		$shaper_queue = "";
1611
	}
1612
	foreach ($iflist as $ifent => $ifname) {
1613
		/*    if the ftp proxy is disabled for this interface then kill pftpx
1614
		 *    instance and continue. note that the helpers for port forwards are
1615
		 *    launched in a  different sequence so we are filtering them out
1616
	         *    here by not including -c {$port} -g 8021 first.
1617
		 */
1618
		 /* only install a ftp helper for enabled interfaces. wan and lan are always enabled. */
1619
		if(stristr($ifname, "opt") <> false)
1620
			if(!isset($config['interfaces'][strtolower($ifname)]['enable']))
1621
				continue;
1622
		$port = 8021 + $interface_counter;
1623
		if(isset($config['interfaces'][$ifname]['disableftpproxy'])) {
1624
			/*    item is disabled.  lets ++ the interface counter and
1625
			 *    keep processing interfaces. kill pftpx if already
1626
			 *    running for this instance.
1627
			 */
1628
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx {$shaper_queue}-c {$port}\" | grep -v grep | sed \"s/  */ /g\" | cut -f2 -d\" \"");
1629
			if($helpers)
1630
				mwexec("/bin/kill {$helpers}");
1631
			$interface_counter++;
1632
		} else {
1633
			/* grab the current interface IP address */
1634
			$int = convert_friendly_interface_to_real_interface_name($ifname);
1635
			$ip = find_interface_ip($int);
1636
			/* are we in routed mode? no source nat rules and not a outside interface? */
1637
			/* If we have advanced outbound nat we skip the FTP proxy, we use ftpsesame */
1638
			if((isset($config['nat']['advancedoutbound']['enable'])) && (! interface_has_gateway($ifname))) {
1639
				$sourcenat = 0;
1640
				/* we are using advanced outbound nat, are we in routing mode? */
1641
				/* if the interface address lies within a outbound NAT source network we should skip */
1642
				if(! empty($config['nat']['advancedoutbound']['rule'])) {
1643
					foreach($config['nat']['advancedoutbound']['rule'] as $natnetwork) {
1644
						if(ip_in_subnet($ip, $natnetwork['source']['network'])) {
1645
							/* if the interface address is matched in the AON Rule we need the ftp proxy */
1646
							$sourcenat++;
1647
						}
1648
					}
1649
				}
1650
				if($sourcenat == 0) {
1651
					if($g['debug'])
1652
						log_error("Config: No AON rule matched for interface {$ifname} - not using FTP proxy");
1653
					mwexec("/usr/local/sbin/ftpsesame -i $int");
1654
					$interface_counter++;
1655
					continue;
1656
				} else {
1657
					if($g['debug'])
1658
						log_error("Config: AON rule matched for interface {$ifname} - using FTP proxy");
1659
				}
1660
			}
1661
			/* if pftpx is already running then do not launch it again */
1662
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx {$shaper_queue}-c {$port}\" | grep -v grep | sed \"s/  */ /g\"");
1663
			if(!$helpers && $ip)
1664
 				mwexec("/usr/local/sbin/pftpx {$shaper_queue}-c {$port} -g 8021 {$ip}");
1665
			if(!$ip)
1666
				mwexec("/usr/local/sbin/ftpsesame {$shaper_queue}-i $int");
1667
			$interface_counter++;
1668
		}
1669
	}
1670
	/* support bridged interfaces.  even they need ftp mojo */
1671
	$num_bridges = find_number_of_created_bridges();
1672
	$num_bridges++;
1673
	for($x=0; $x<$num_bridges; $x++) {
1674
		mwexec("/usr/local/sbin/ftpsesame {$shaper_queue}-i bridge{$x}");
1675
	}
1676
}
1677

    
1678
function cleanup_backupcache($revisions = 30) {
1679
	global $g;
1680
	$i = false;
1681
	config_lock();
1682
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1683
		conf_mount_rw();
1684
		$backups = get_backups();
1685
		$newbaks = array();
1686
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1687
		$baktimes = $backups['versions'];
1688
		$tocache = array();
1689
		unset($backups['versions']);
1690
   		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1691
   			if(filesize($backup) == 0) {
1692
   				unlink($backup);
1693
   				continue;
1694
   			}
1695
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1696
            if(!in_array($tocheck, $baktimes)) {
1697
				$i = true;
1698
				if($g['booting'])
1699
					print " " . $tocheck . "a";
1700
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1701
				if($newxml == "-1") {
1702
					unlink($backup);
1703
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1704
					continue;
1705
				}
1706
				if($newxml['revision']['description'] == "")
1707
					$newxml['revision']['description'] = "Unknown";
1708
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1709
			}
1710
    	}
1711
		foreach($backups as $checkbak) {
1712

    
1713
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1714
				$newbaks[] = $checkbak;
1715
			} else {
1716
				$i = true;
1717
				if($g['booting']) print " " . $tocheck . "r";
1718
			}
1719
		}
1720
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1721
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1722
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1723
			foreach($toslice as $sliced)
1724
				$newcache[$sliced] = $tocache[$sliced];
1725
			foreach($tocache as $version => $versioninfo) {
1726
				if(!in_array($version, array_keys($newcache))) {
1727
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1728
					if($g['booting']) print " " . $tocheck . "d";
1729
				}
1730
			}
1731
			$tocache = $newcache;
1732
		}
1733
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1734
        fwrite($bakout, serialize($tocache));
1735
		fclose($bakout);
1736
		conf_mount_ro();
1737
	}
1738
	if($g['booting']) {
1739
		if($i) {
1740
			print "done.\n";
1741
		}
1742
	}
1743
	config_unlock();
1744
}
1745

    
1746
function get_backups() {
1747
	global $g;
1748
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1749
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1750
		$bakvers = array_keys($confvers);
1751
		$toreturn = array();
1752
		sort($bakvers);
1753
		// 	$bakvers = array_reverse($bakvers);
1754
		foreach(array_reverse($bakvers) as $bakver)
1755
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1756
	} else {
1757
		return false;
1758
	}
1759
	$toreturn['versions'] = $bakvers;
1760
	return $toreturn;
1761
}
1762

    
1763
function backup_config() {
1764
	global $config, $g;
1765

    
1766
	if($g['platform'] == "cdrom")
1767
		return;
1768

    
1769
	conf_mount_rw();
1770

    
1771
	/* Create backup directory if needed */
1772
	safe_mkdir("{$g['cf_conf_path']}/backup");
1773

    
1774
    if($config['revision']['time'] == "") {
1775
            $baktime = 0;
1776
    } else {
1777
            $baktime = $config['revision']['time'];
1778
    }
1779
    if($config['revision']['description'] == "") {
1780
            $bakdesc = "Unknown";
1781
    } else {
1782
            $bakdesc = $config['revision']['description'];
1783
    }
1784
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1785
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1786
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1787
    } else {
1788
            $backupcache = array();
1789
    }
1790
    $backupcache[$baktime] = array('description' => $bakdesc);
1791
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1792
    fwrite($bakout, serialize($backupcache));
1793
    fclose($bakout);
1794

    
1795
	conf_mount_ro();
1796

    
1797
	return true;
1798
}
1799

    
1800
function mute_kernel_msgs() {
1801
	exec("/sbin/conscontrol mute on");
1802
}
1803

    
1804
function unmute_kernel_msgs() {
1805
	exec("/sbin/conscontrol mute off");
1806
}
1807

    
1808
function start_devd() {
1809
	exec("/sbin/devd");
1810
	sleep(1);
1811
	if(file_exists("/tmp/rc.linkup"))
1812
		unlink("/tmp/rc.linkup");
1813
}
1814

    
1815
function is_interface_mismatch() {
1816
	global $config, $g;
1817
	$lan_if = $config['interfaces']['lan']['if'];
1818
	$wan_if = get_real_wan_interface();
1819
	$do_assign = 0;
1820
	/* we need to ignore the vlan interface checks) */
1821
	if (stristr($lan_if, "vlan") == false and stristr($wan_if, "vlan") == false) {
1822
		if (does_interface_exist($lan_if) == false)
1823
			$do_assign = 1;
1824
		if ($config['interfaces']['wan']['ipaddr'] <> "pppoe" && $config['interfaces']['wan']['ipaddr'] <> "pptp" && $do_assign == 0)
1825
			if (does_interface_exist($wan_if) == false)
1826
				$do_assign = 1;
1827
	}
1828
	/* XXX: enumerate OPT interfaces looking for mismatches */
1829
	if (file_exists("{$g['tmp_path']}/assign_complete"))
1830
		return false;
1831
	if ($do_assign == 1)
1832
		return true;
1833
	else
1834
		return false;
1835
}
1836

    
1837
function set_device_perms() {
1838
	$devices = array(
1839
		'pf'	=> array(	'user'	=> 'proxy',
1840
					'group'	=> 'proxy',
1841
					'mode'	=> 0660),
1842
		);
1843

    
1844
	foreach ($devices as $name => $attr) {
1845
		$path = "/dev/$name";
1846
		if (file_exists($path)) {
1847
			chown($path, $attr['user']);
1848
			chgrp($path, $attr['group']);
1849
			chmod($path, $attr['mode']);
1850
		}
1851
	}
1852
}
1853

    
1854
if($g['booting']) echo ".";
1855
$config = parse_config();
1856

    
1857
?>
(5-5/27)