Project

General

Profile

Download (49.1 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
				restore_backup("/cf/conf/backup/{$last_backup}");
162
			} else {
163
				/* no device found, print an error and die */
164
				echo <<<EOD
165

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

    
172

    
173
EOD;
174

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

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

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

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

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

    
199
/****f* config/parse_config
200
 * NAME
201
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
202
 * INPUTS
203
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
204
 * RESULT
205
 *   $config      - array containing all configuration variables
206
 ******/
207
function parse_config($parse = false) {
208
	global $g;
209
	if($g['booting']) echo ".";
210
	config_lock();
211
	if(!$parse) {
212
		if(file_exists($g['tmp_path'] . '/config.cache')) {
213
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
214
			if(is_null($config)) {
215
				config_unlock();
216
				parse_config(true);
217
			}
218
		} else {
219
			config_unlock();
220
			if(!file_exists($g['conf_path'] . "/config.xml")) {
221
				log_error("No config.xml found, attempting last known config restore.");
222
				$last_backup = discover_last_backup();
223
				if ($last_backup)
224
					restore_backup("/cf/conf/backup/{$last_backup}");
225
				else
226
					log_error("Could not restore config.xml.");
227
			}
228
			$config = parse_config(true);
229
		}
230
	} else {
231
		if(!file_exists($g['conf_path'] . "/config.xml")) {
232
			if($g['booting']) echo ".";
233
			log_error("No config.xml found, attempting last known config restore.");
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_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
241
		generate_config_cache($config);
242
	}
243
	if($g['booting']) echo ".";
244
	alias_make_table($config);
245
	config_unlock();
246

    
247
	/*    override some global configuration parms if they exist
248
	 *    instead of hard coding these checks into the codebase
249
     */
250
	if($config['pptp']['n_pptp_units'])
251
		$g['n_pptp_units'] = $config['pptp']['n_pptp_units'];
252
	if($config['pptp']['pptp_subnet'])
253
		$g['pptp_subnet'] = $config['pptp']['pptp_subnet'];
254

    
255
	if($config['pppoe']['n_pppoe_units'])
256
		$g['n_pppoe_units'] = $config['pppoe']['n_pppoe_units'];
257
	if($config['pppoe']['pppoe_subnet'])
258
		$g['pppoe_subnet'] = $config['pppoe']['pppoe_subnet'];
259

    
260
	return $config;
261
}
262

    
263
/****f* config/generate_config_cache
264
 * NAME
265
 *   generate_config_cache - Write serialized configuration to cache.
266
 * INPUTS
267
 *   $config	- array containing current firewall configuration
268
 * RESULT
269
 *   boolean	- true on completion
270
 ******/
271
function generate_config_cache($config) {
272
	global $g;
273
	conf_mount_rw();
274
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
275
	fwrite($configcache, serialize($config));
276
	fclose($configcache);
277
	conf_mount_ro();
278
	return true;
279
}
280

    
281
function discover_last_backup() {
282
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
283
		$last_backup = "";
284
        foreach($backups as $backup)
285
        	if($backup)
286
	        	$last_backup = $backup;
287
        return $last_backup;
288
}
289

    
290
function restore_backup($file) {
291
	if(file_exists($file)) {
292
		conf_mount_rw();
293
		system("cp $file /cf/conf/config.xml");
294
	}
295
}
296

    
297
/****f* config/parse_config_bootup
298
 * NAME
299
 *   parse_config_bootup - Bootup-specific configuration checks.
300
 * RESULT
301
 *   null
302
 ******/
303
function parse_config_bootup() {
304
	global $config, $g, $noparseconfig;
305
	if($g['booting']) echo ".";
306
	if (!$noparseconfig) {
307
		if (!file_exists("{$g['conf_path']}/config.xml")) {
308
			config_lock();
309
			if ($g['booting']) {
310
				if (strstr($g['platform'], "cdrom")) {
311
					/* try copying the default config. to the floppy */
312
					echo "Resetting factory defaults...\n";
313
					reset_factory_defaults();
314
					if (file_exists("{$g['conf_path']}/config.xml")) {
315
						/* do nothing, we have a file. */
316
					} else {
317
						echo "No XML configuration file found - using factory defaults.\n";
318
						echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
319
						echo "file is inserted. If it isn't, your configuration changes will be lost\n";
320
						echo "on reboot.\n";
321
					}
322
				} else {
323
					$last_backup = discover_last_backup();
324
					if($last_backup) {
325
						log_error("No config.xml found, attempting last known config restore.");
326
						restore_backup("/cf/conf/backup/{$last_backup}");
327
					}
328
					if(!file_exists("{$g['conf_path']}/config.xml")) {
329
						echo "XML configuration file not found.  pfSense cannot continue booting.\n";
330
						mwexec("/sbin/halt");
331
						exit;
332
					}
333
					log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
334
				}
335
			} else {
336
				config_unlock();
337
				exit(0);
338
			}
339
		}
340
	}
341

    
342
	parse_config(true);
343

    
344
	if ((float)$config['version'] > (float)$g['latest_config']) {
345
		echo <<<EOD
346

    
347

    
348
*******************************************************************************
349
* WARNING!                                                                    *
350
* The current configuration has been created with a newer version of pfSense  *
351
* than this one! This can lead to serious misbehavior and even security       *
352
* holes! You are urged to either upgrade to a newer version of pfSense or     *
353
* revert to the default configuration immediately!                            *
354
*******************************************************************************
355

    
356

    
357
EOD;
358
		}
359

    
360
	/* make alias table (for faster lookups) */
361
	alias_make_table($config);
362
	config_unlock();
363
}
364

    
365
/****f* config/conf_mount_rw
366
 * NAME
367
 *   conf_mount_rw - Mount filesystems read/write.
368
 * RESULT
369
 *   null
370
 ******/
371
/* mount flash card read/write */
372
function conf_mount_rw() {
373
	global $g;
374

    
375
	/* do not mount on cdrom platform */
376
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
377
		return;
378
		
379
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
380
	if($status <> 0) {
381
		if($g['booting'])
382
			echo "Disk is dirty.  Running fsck -y\n";
383
		mwexec("/sbin/fsck -y {$g['cf_path']}");
384
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
385
	}
386

    
387
	/*    if the platform is soekris or wrap or pfSense, lets mount the
388
	 *    compact flash cards root.
389
         */
390
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
391
	   or $g['platform'] == "embedded") {
392
		$status = mwexec("/sbin/mount -u -w /");
393
		/* we could not mount this correctly.  kick off fsck */
394
		if($status <> 0) {
395
			log_error("File system is dirty.  Launching FSCK for /");
396
			mwexec("/sbin/fsck -y /");
397
			$status = mwexec("/sbin/mount -u -w /");
398
		}
399
	}
400
}
401

    
402
/****f* config/conf_mount_ro
403
 * NAME
404
 *   conf_mount_ro - Mount filesystems readonly.
405
 * RESULT
406
 *   null
407
 ******/
408
function conf_mount_ro() {
409
	global $g;
410

    
411
	if($g['booting'] == true)
412
		return;
413

    
414
	/* firmare upgrade in progress */
415
	if(file_exists($g['varrun_path'] . "/fwup.enabled"))
416
		return;
417

    
418
	/* do not umount if generating ssh keys */
419
	if(file_exists("/tmp/keys_generating"))
420
		return;
421

    
422
	/* do not umount on cdrom or pfSense platforms */
423
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
424
		return;
425

    
426
	/* sync data, then force a remount of /cf */
427
	mwexec("/bin/sync");
428
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
429
	mwexec("/sbin/mount -u -r -f /");
430
}
431

    
432
/****f* config/convert_config
433
 * NAME
434
 *   convert_config - Attempt to update config.xml.
435
 * DESCRIPTION
436
 *   convert_config() reads the current global configuration
437
 *   and attempts to convert it to conform to the latest
438
 *   config.xml version. This allows major formatting changes
439
 *   to be made with a minimum of breakage.
440
 * RESULT
441
 *   null
442
 ******/
443
/* convert configuration, if necessary */
444
function convert_config() {
445
	global $config, $g;
446

    
447
	if ($config['version'] == $g['latest_config'])
448
		return;		/* already at latest version */
449

    
450
	// Save off config version
451
	$prev_version = $config['version'];
452

    
453
	/* convert 1.0 -> 1.1 */
454
	if ($config['version'] <= 1.0) {
455
		$opti = 1;
456
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
457

    
458
		/* convert DMZ to optional, if necessary */
459
		if (isset($config['interfaces']['dmz'])) {
460

    
461
			$dmzcfg = &$config['interfaces']['dmz'];
462

    
463
			if ($dmzcfg['if']) {
464
				$config['interfaces']['opt' . $opti] = array();
465
				$optcfg = &$config['interfaces']['opt' . $opti];
466

    
467
				$optcfg['enable'] = $dmzcfg['enable'];
468
				$optcfg['descr'] = "DMZ";
469
				$optcfg['if'] = $dmzcfg['if'];
470
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
471
				$optcfg['subnet'] = $dmzcfg['subnet'];
472

    
473
				$ifmap['dmz'] = "opt" . $opti;
474
				$opti++;
475
			}
476

    
477
			unset($config['interfaces']['dmz']);
478
		}
479

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

    
483
			if (!$config['interfaces']['wlan' . $i]['if']) {
484
				unset($config['interfaces']['wlan' . $i]);
485
				continue;
486
			}
487

    
488
			$wlancfg = &$config['interfaces']['wlan' . $i];
489
			$config['interfaces']['opt' . $opti] = array();
490
			$optcfg = &$config['interfaces']['opt' . $opti];
491

    
492
			$optcfg['enable'] = $wlancfg['enable'];
493
			$optcfg['descr'] = "WLAN" . $i;
494
			$optcfg['if'] = $wlancfg['if'];
495
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
496
			$optcfg['subnet'] = $wlancfg['subnet'];
497
			$optcfg['bridge'] = $wlancfg['bridge'];
498

    
499
			$optcfg['wireless'] = array();
500
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
501
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
502
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
503
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
504

    
505
			$ifmap['wlan' . $i] = "opt" . $opti;
506

    
507
			unset($config['interfaces']['wlan' . $i]);
508
			$opti++;
509
		}
510

    
511
		/* convert filter rules */
512
		$n = count($config['filter']['rule']);
513
		for ($i = 0; $i < $n; $i++) {
514

    
515
			$fr = &$config['filter']['rule'][$i];
516

    
517
			/* remap interface */
518
			if (array_key_exists($fr['interface'], $ifmap))
519
				$fr['interface'] = $ifmap[$fr['interface']];
520
			else {
521
				/* remove the rule */
522
				echo "\nWarning: filter rule removed " .
523
					"(interface '{$fr['interface']}' does not exist anymore).";
524
				unset($config['filter']['rule'][$i]);
525
				continue;
526
			}
527

    
528
			/* remap source network */
529
			if (isset($fr['source']['network'])) {
530
				if (array_key_exists($fr['source']['network'], $ifmap))
531
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
532
				else {
533
					/* remove the rule */
534
					echo "\nWarning: filter rule removed " .
535
						"(source network '{$fr['source']['network']}' does not exist anymore).";
536
					unset($config['filter']['rule'][$i]);
537
					continue;
538
				}
539
			}
540

    
541
			/* remap destination network */
542
			if (isset($fr['destination']['network'])) {
543
				if (array_key_exists($fr['destination']['network'], $ifmap))
544
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
545
				else {
546
					/* remove the rule */
547
					echo "\nWarning: filter rule removed " .
548
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
549
					unset($config['filter']['rule'][$i]);
550
					continue;
551
				}
552
			}
553
		}
554

    
555
		/* convert shaper rules */
556
		$n = count($config['pfqueueing']['rule']);
557
		if (is_array($config['pfqueueing']['rule']))
558
			for ($i = 0; $i < $n; $i++) {
559

    
560
			$fr = &$config['pfqueueing']['rule'][$i];
561

    
562
			/* remap interface */
563
			if (array_key_exists($fr['interface'], $ifmap))
564
				$fr['interface'] = $ifmap[$fr['interface']];
565
			else {
566
				/* remove the rule */
567
				echo "\nWarning: traffic shaper rule removed " .
568
					"(interface '{$fr['interface']}' does not exist anymore).";
569
				unset($config['pfqueueing']['rule'][$i]);
570
				continue;
571
			}
572

    
573
			/* remap source network */
574
			if (isset($fr['source']['network'])) {
575
				if (array_key_exists($fr['source']['network'], $ifmap))
576
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
577
				else {
578
					/* remove the rule */
579
					echo "\nWarning: traffic shaper rule removed " .
580
						"(source network '{$fr['source']['network']}' does not exist anymore).";
581
					unset($config['pfqueueing']['rule'][$i]);
582
					continue;
583
				}
584
			}
585

    
586
			/* remap destination network */
587
			if (isset($fr['destination']['network'])) {
588
				if (array_key_exists($fr['destination']['network'], $ifmap))
589
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
590
				else {
591
					/* remove the rule */
592
					echo "\nWarning: traffic shaper rule removed " .
593
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
594
					unset($config['pfqueueing']['rule'][$i]);
595
					continue;
596
				}
597
			}
598
		}
599

    
600
		$config['version'] = "1.1";
601
	}
602

    
603
	/* convert 1.1 -> 1.2 */
604
	if ($config['version'] <= 1.1) {
605
		/* move LAN DHCP server config */
606
		$tmp = $config['dhcpd'];
607
		$config['dhcpd'] = array();
608
		$config['dhcpd']['lan'] = $tmp;
609

    
610
		/* encrypt password */
611
		$config['system']['password'] = crypt($config['system']['password']);
612

    
613
		$config['version'] = "1.2";
614
	}
615

    
616
	/* convert 1.2 -> 1.3 */
617
	if ($config['version'] <= 1.2) {
618
		/* convert advanced outbound NAT config */
619
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
620
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
621
			$src = $curent['source'];
622
			$curent['source'] = array();
623
			$curent['source']['network'] = $src;
624
			$curent['destination'] = array();
625
			$curent['destination']['any'] = true;
626
		}
627

    
628
		/* add an explicit type="pass" to all filter rules to make things consistent */
629
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
630
			$config['filter']['rule'][$i]['type'] = "pass";
631
		}
632

    
633
		$config['version'] = "1.3";
634
	}
635

    
636
	/* convert 1.3 -> 1.4 */
637
	if ($config['version'] <= 1.3) {
638
		/* convert shaper rules (make pipes) */
639
		if (is_array($config['pfqueueing']['rule'])) {
640
			$config['pfqueueing']['pipe'] = array();
641

    
642
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
643
				$curent = &$config['pfqueueing']['rule'][$i];
644

    
645
				/* make new pipe and associate with this rule */
646
				$newpipe = array();
647
				$newpipe['descr'] = $curent['descr'];
648
				$newpipe['bandwidth'] = $curent['bandwidth'];
649
				$newpipe['delay'] = $curent['delay'];
650
				$newpipe['mask'] = $curent['mask'];
651
				$config['pfqueueing']['pipe'][$i] = $newpipe;
652

    
653
				$curent['targetpipe'] = $i;
654

    
655
				unset($curent['bandwidth']);
656
				unset($curent['delay']);
657
				unset($curent['mask']);
658
			}
659
		}
660

    
661
		$config['version'] = "1.4";
662
	}
663

    
664
	/* Convert 1.4 -> 1.5 */
665
	if ($config['version'] <= 1.4) {
666

    
667
		/* Default route moved */
668
		if (isset($config['interfaces']['wan']['gateway']))
669
			if ($config['interfaces']['wan']['gateway'] <> "")
670
				$config['interfaces']['wan']['gateway'] = $config['interfaces']['wan']['gateway'];
671
		unset($config['interfaces']['wan']['gateway']);
672

    
673
                /* Queues are no longer interface specific */
674
                if (isset($config['interfaces']['lan']['schedulertype']))
675
                        unset($config['interfaces']['lan']['schedulertype']);
676
                if (isset($config['interfaces']['wan']['schedulertype']))
677
                        unset($config['interfaces']['wan']['schedulertype']);
678

    
679
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
680
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
681
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
682
                }
683

    
684
		$config['version'] = "1.5";
685
	}
686

    
687
	/* Convert 1.5 -> 1.6 */
688
	if ($config['version'] <= 1.5) {
689
		/* Alternate firmware URL moved */
690
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
691
			$config['system']['alt_firmware_url'] = array();
692
			$config['system']['alt_firmware_url']['enabled'] = "";
693
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
694
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
695
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
696
		} else {
697
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
698
		}
699

    
700
		$config['version'] = "1.6";
701
	}
702

    
703
	/* Convert 1.6 -> 1.7 */
704
	if ($config['version'] <= 1.6) {
705
		/* wipe previous shaper configuration */
706
		unset($config['shaper']['queue']);
707
		unset($config['shaper']['rule']);
708
		unset($config['interfaces']['wan']['bandwidth']);
709
		unset($config['interfaces']['wan']['bandwidthtype']);
710
		unset($config['interfaces']['lan']['bandwidth']);
711
		unset($config['interfaces']['lan']['bandwidthtype']);
712
		$config['shaper']['enable'] = FALSE;
713
		$config['version'] = "1.7";
714
	}
715
	/* Convert 1.7 -> 1.8 */
716
	if ($config['version'] <= 1.7) {
717
		if(isset($config['proxyarp']) && is_array($config['proxyarp']['proxyarpnet'])) {
718
			$proxyarp = &$config['proxyarp']['proxyarpnet'];
719
			foreach($proxyarp as $arpent){
720
				$vip = array();
721
				$vip['mode'] = "proxyarp";
722
				$vip['interface'] = $arpent['interface'];
723
				$vip['descr'] = $arpent['descr'];
724
				if (isset($arpent['range'])) {
725
					$vip['range'] = $arpent['range'];
726
					$vip['type'] = "range";
727
				} else {
728
					$subnet = explode('/', $arpent['network']);
729
					$vip['subnet'] = $subnet[0];
730
					if (isset($subnet[1])) {
731
						$vip['subnet_bits'] = $subnet[1];
732
						$vip['type'] = "network";
733
					} else {
734
						$vip['subnet_bits'] = "32";
735
						$vip['type'] = "single";
736
					}
737
				}
738
				$config['virtualip']['vip'][] = $vip;
739
			}
740
			unset($config['proxyarp']);
741
		}
742
		if(isset($config['installedpackages']) && isset($config['installedpackages']['carp']) && is_array($config['installedpackages']['carp']['config'])) {
743
			$carp = &$config['installedpackages']['carp']['config'];
744
			foreach($carp as $carpent){
745
				$vip = array();
746
				$vip['mode'] = "carp";
747
				$vip['interface'] = "AUTO";
748
				$vip['descr'] = "CARP vhid {$carpent['vhid']}";
749
				$vip['type'] = "single";
750
				$vip['vhid'] = $carpent['vhid'];
751
				$vip['advskew'] = $carpent['advskew'];
752
				$vip['password'] = $carpent['password'];
753
				$vip['subnet'] = $carpent['ipaddress'];
754
				$vip['subnet_bits'] = $carpent['netmask'];
755
				$config['virtualip']['vip'][] = $vip;
756
			}
757
			unset($config['installedpackages']['carp']);
758
		}
759
		/* Server NAT is no longer needed */
760
		unset($config['nat']['servernat']);
761

    
762
		/* enable SSH */
763
		if ($config['version'] == "1.8") {
764
			$config['system']['sshenabled'] = true;
765
		}
766

    
767
		$config['version'] = "1.9";
768
	}
769

    
770
	/* Convert 1.8 -> 1.9 */
771
	if ($config['version'] <= 1.8) {
772
		$config['theme']="metallic";
773
		$config['version'] = "1.9";
774
	}
775
	/* Convert 1.9 -> 2.0 */
776
	if ($config['version'] <= 1.9) {
777
		if(is_array($config['ipsec']['tunnel'])) {
778
			reset($config['ipsec']['tunnel']);
779
			while (list($index, $tunnel) = each($config['ipsec']['tunnel'])) {
780
				/* Sanity check on required variables */
781
				/* This fixes bogus <tunnel> entries - remnant of bug #393 */
782
				if (!isset($tunnel['local-subnet']) && !isset($tunnel['remote-subnet'])) {
783
					unset($config['ipsec']['tunnel'][$tunnel]);
784
				}
785
			}
786
        	}
787
		$config['version'] = "2.0";
788
	}
789
	/* Convert 2.0 -> 2.1 */
790
	if ($config['version'] <= 2.0) {
791
		/* shaper scheduler moved */
792
		if(isset($config['system']['schedulertype'])) {
793
			$config['shaper']['schedulertype'] = $config['system']['schedulertype'];
794
			unset($config['system']['schedulertype']);
795
		}
796
		$config['version'] = "2.1";
797
	}
798
	/* Convert 2.1 -> 2.2 */
799
	if ($config['version'] <= 2.1) {
800
		/* move gateway to wan interface */
801
		$config['interfaces']['wan']['gateway'] = $config['system']['gateway'];
802
		$config['version'] = "2.2";
803
	}
804
	/* Convert 2.2 -> 2.3 */
805
	if ($config['version'] <= 2.2) {
806
		if(isset($config['shaper'])) {
807
			/* wipe previous shaper configuration */
808
			unset($config['shaper']);
809
		}
810
		$config['version'] = "2.3";
811
	}
812

    
813
	/* Convert 2.4 -> 2.5 */
814
	if ($config['version'] <= 2.4) {
815
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
816
		unset($config['system']['use_rrd_gateway']);
817
 		$config['version'] = "2.5";
818
	}
819

    
820
	/* Convert 2.5 -> 2.6 */
821
	if ($config['version'] <= 2.5) {
822
		$cron_item = array();
823
		$cron_item['minute'] = "0";
824
		$cron_item['hour'] = "*";
825
		$cron_item['mday'] = "*";
826
		$cron_item['month'] = "*";
827
		$cron_item['wday'] = "*";
828
		$cron_item['who'] = "root";
829
		$cron_item['command'] = "/usr/bin/nice -n20 newsyslog";
830

    
831
		$config['cron']['item'][] = $cron_item;
832

    
833
		$cron_item = array();
834
		$cron_item['minute'] = "1,31";
835
		$cron_item['hour'] = "0-5";
836
		$cron_item['mday'] = "*";
837
		$cron_item['month'] = "*";
838
		$cron_item['wday'] = "*";
839
		$cron_item['who'] = "root";
840
		$cron_item['command'] = "/usr/bin/nice -n20 adjkerntz -a";
841

    
842
		$config['cron']['item'][] = $cron_item;
843

    
844
		$cron_item = array();
845
		$cron_item['minute'] = "1";
846
		$cron_item['hour'] = "*";
847
		$cron_item['mday'] = "1";
848
		$cron_item['month'] = "*";
849
		$cron_item['wday'] = "*";
850
		$cron_item['who'] = "root";
851
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.update_bogons.sh";
852

    
853
		$config['cron']['item'][] = $cron_item;
854

    
855
		$cron_item = array();
856
		$cron_item['minute'] = "*/60";
857
		$cron_item['hour'] = "*";
858
		$cron_item['mday'] = "*";
859
		$cron_item['month'] = "*";
860
		$cron_item['wday'] = "*";
861
		$cron_item['who'] = "root";
862
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 sshlockout";
863

    
864
		$config['cron']['item'][] = $cron_item;
865

    
866
		$cron_item = array();
867
		$cron_item['minute'] = "1";
868
		$cron_item['hour'] = "1";
869
		$cron_item['mday'] = "*";
870
		$cron_item['month'] = "*";
871
		$cron_item['wday'] = "*";
872
		$cron_item['who'] = "root";
873
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.dyndns.update";
874

    
875
		$config['cron']['item'][] = $cron_item;
876

    
877
		$cron_item = array();
878
		$cron_item['minute'] = "*/60";
879
		$cron_item['hour'] = "*";
880
		$cron_item['mday'] = "*";
881
		$cron_item['month'] = "*";
882
		$cron_item['wday'] = "*";
883
		$cron_item['who'] = "root";
884
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 virusprot";
885

    
886
		$config['cron']['item'][] = $cron_item;
887

    
888
		$cron_item = array();
889
		$cron_item['minute'] = "*/60";
890
		$cron_item['hour'] = "*";
891
		$cron_item['mday'] = "*";
892
		$cron_item['month'] = "*";
893
		$cron_item['wday'] = "*";
894
		$cron_item['who'] = "root";
895
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -t 1800 snort2c";
896

    
897
		$config['cron']['item'][] = $cron_item;
898

    
899
		$cron_item = array();
900
		$cron_item['minute'] = "*/5";
901
		$cron_item['hour'] = "*";
902
		$cron_item['mday'] = "*";
903
		$cron_item['month'] = "*";
904
		$cron_item['wday'] = "*";
905
		$cron_item['who'] = "root";
906
		$cron_item['command'] = "/usr/local/bin/checkreload.sh";
907

    
908
		$config['cron']['item'][] = $cron_item;
909

    
910
		/* write crontab entries to file */
911
		configure_cron();
912

    
913
 		$config['version'] = "2.6";
914
	}
915

    
916
	/* Convert 2.6 -> 2.7 */
917
	if ($config['version'] <= 2.6) {
918
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
919
		unset($config['system']['use_rrd_gateway']);
920
		$config['version'] = "2.7";
921
	}
922

    
923
	/* Convert 2.7 -> 2.8 */
924
	if ($config['version'] <= 2.7) {
925
		$founditem = false;
926
		foreach($config['cron']['item'] as $cronitem) {
927
			if($cronitem['command'] == "/usr/local/bin/checkreload.sh")
928
				$founditem = true;
929
		}
930
		if($founditem == false) {
931
			$cron_item = array();
932
			$cron_item['minute'] = "*/5";
933
			$cron_item['hour'] = "*";
934
			$cron_item['mday'] = "*";
935
			$cron_item['month'] = "*";
936
			$cron_item['wday'] = "*";
937
			$cron_item['who'] = "root";
938
			$cron_item['command'] = "/usr/local/bin/checkreload.sh";
939
			$config['cron']['item'][] = $cron_item;
940
		}
941
		$config['version'] = "2.8";
942
	}
943

    
944
	/* Convert 2.8 -> 2.9 */
945
	if ($config['version'] <= 2.8) {
946
		$rule_item = array();
947
		$a_filter = &$config['filter']['rule'];
948
		$rule_item['interface'] = "enc0";
949
		$rule_item['type'] = "pass";
950
		$rule_item['source']['any'] = true;
951
		$rule_item['destination']['any'] = true;
952
		$rule_item['descr'] = "Permit IPSEC traffic.";
953
		$rule_item['statetype'] = "keep state";
954
		$a_filter[] = $rule_item;
955
		$config['version'] = "2.9";
956
	}
957

    
958
	if ($prev_version != $config['version'])
959
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
960
}
961

    
962
/****f* config/write_config
963
 * NAME
964
 *   write_config - Backup and write the firewall configuration.
965
 * DESCRIPTION
966
 *   write_config() handles backing up the current configuration,
967
 *   applying changes, and regenerating the configuration cache.
968
 * INPUTS
969
 *   $desc	- string containing the a description of configuration changes
970
 *   $backup	- boolean: do not back up current configuration if false.
971
 * RESULT
972
 *   null
973
 ******/
974
/* save the system configuration */
975
function write_config($desc="Unknown", $backup = true) {
976
	global $config, $g;
977

    
978
	if($backup)
979
		backup_config();
980

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

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

    
988
	$config['revision']['description'] = $desc;
989
	$config['revision']['time'] = $changetime;
990

    
991
	config_lock();
992

    
993
	/* generate configuration XML */
994
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
995

    
996
	conf_mount_rw();
997

    
998
	/* write new configuration */
999
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
1000
	if (!$fd)
1001
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
1002
	fwrite($fd, $xmlconfig);
1003
	fclose($fd);
1004

    
1005
	if($g['platform'] == "embedded") {
1006
		/*   backup last config.xml and remove all others to avoid
1007
		 *   filling up the compact flash dedicated config partition
1008
		 */
1009
		$last_backup = discover_last_backup();
1010
		mwexec("/bin/mv /cf/conf/backup/{$last_backup} /tmp/lastconfig.xml");
1011
		mwexec("/bin/rm /cf/conf/backup/*");
1012
		mwexec("/bin/mv /tmp/lastconfig.xml /cf/conf/backup/{$last_backup}");
1013
	}
1014

    
1015
	if($g['booting'] <> true) {
1016
		conf_mount_ro();
1017
	}
1018

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

    
1022
	/* write config cache */
1023
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
1024
	if ($fd) {
1025
		fwrite($fd, serialize($config));
1026
		fclose($fd);
1027
	}
1028

    
1029
	config_unlock();
1030

    
1031
	/* tell kernel to sync fs data */
1032
	mwexec("/bin/sync");
1033

    
1034
	return $config;
1035
}
1036

    
1037
/****f* config/reset_factory_defaults
1038
 * NAME
1039
 *   reset_factory_defaults - Reset the system to its default configuration.
1040
 * RESULT
1041
 *   integer	- indicates completion
1042
 ******/
1043
function reset_factory_defaults() {
1044
	global $g;
1045

    
1046
	config_lock();
1047
	conf_mount_rw();
1048

    
1049
	/* create conf directory, if necessary */
1050
	safe_mkdir("{$g['cf_conf_path']}");
1051

    
1052
	/* clear out /conf */
1053
	$dh = opendir($g['conf_path']);
1054
	while ($filename = readdir($dh)) {
1055
		if (($filename != ".") && ($filename != "..")) {
1056
			unlink_if_exists($g['conf_path'] . "/" . $filename);
1057
		}
1058
	}
1059
	closedir($dh);
1060

    
1061
	/* copy default configuration */
1062
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
1063

    
1064
	/* call the wizard */
1065
	touch("/conf/trigger_initial_wizard");
1066

    
1067
	conf_mount_ro();
1068
	config_unlock();
1069

    
1070
	return 0;
1071
}
1072

    
1073
function config_restore($conffile) {
1074
	global $config, $g;
1075

    
1076
	if (!file_exists($conffile))
1077
		return 1;
1078

    
1079
    config_lock();
1080
    conf_mount_rw();
1081

    
1082
    backup_config();
1083
    copy($conffile, "{$g['cf_conf_path']}/config.xml");
1084
	$config = parse_config(true);
1085
    write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
1086

    
1087
    conf_mount_ro();
1088
    config_unlock();
1089

    
1090
    return 0;
1091
}
1092

    
1093
function config_install($conffile) {
1094
	global $config, $g;
1095

    
1096
	if (!file_exists($conffile))
1097
		return 1;
1098

    
1099
	if (!config_validate("{$g['conf_path']}/config.xml"))
1100
		return 1;
1101

    
1102
	if($g['booting'] == true)
1103
		echo "Installing configuration...\n";
1104

    
1105
    config_lock();
1106
    conf_mount_rw();
1107

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

    
1110
	/* unlink cache file if it exists */
1111
	if(file_exists("{$g['tmp_path']}/config.cache"))
1112
		unlink("{$g['tmp_path']}/config.cache");
1113

    
1114
    conf_mount_ro();
1115
    config_unlock();
1116

    
1117
    return 0;
1118
}
1119

    
1120
function config_validate($conffile) {
1121

    
1122
	global $g, $xmlerr;
1123

    
1124
	$xml_parser = xml_parser_create();
1125

    
1126
	if (!($fp = fopen($conffile, "r"))) {
1127
		$xmlerr = "XML error: unable to open file";
1128
		return false;
1129
	}
1130

    
1131
	while ($data = fread($fp, 4096)) {
1132
		if (!xml_parse($xml_parser, $data, feof($fp))) {
1133
			$xmlerr = sprintf("%s at line %d",
1134
						xml_error_string(xml_get_error_code($xml_parser)),
1135
						xml_get_current_line_number($xml_parser));
1136
			return false;
1137
		}
1138
	}
1139
	xml_parser_free($xml_parser);
1140

    
1141
	fclose($fp);
1142

    
1143
	return true;
1144
}
1145

    
1146
/*   lock configuration file, decide that the lock file
1147
 *   is stale after 10 seconds
1148
 */
1149
function config_lock() {
1150
	global $g, $process_lock;
1151

    
1152
	/* No need to continue if we're the ones holding the lock */
1153
	if ($process_lock)
1154
		return;
1155

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

    
1158
	$n = 0;
1159
	while ($n < 10) {
1160
		/* open the lock file in append mode to avoid race condition */
1161
		if ($fd = @fopen($lockfile, "x")) {
1162
			/* succeeded */
1163
			$process_lock = true;
1164
			fclose($fd);
1165
			return;
1166
		} else {
1167
			/* file locked, wait and try again */
1168
			$process_lock = false;
1169
			sleep(1);
1170
			$n++;
1171
		}
1172
	}
1173
}
1174

    
1175
/* unlock configuration file */
1176
function config_unlock() {
1177
	global $g, $process_lock;
1178

    
1179
	$lockfile = "{$g['varrun_path']}/config.lock";
1180
	$process_lock = false;
1181

    
1182
	unlink_if_exists($lockfile);
1183
}
1184

    
1185
function set_networking_interfaces_ports() {
1186
	global $noreboot;
1187
	global $config;
1188
	global $g;
1189
	global $fp;
1190

    
1191
	$fp = fopen('php://stdin', 'r');
1192

    
1193
	$memory = get_memory();
1194
	$avail = $memory[0];
1195

    
1196
	if($avail < 115) {
1197
		echo "\n\n\n";
1198
		echo "DANGER!  WARNING!\n\n";
1199
		echo "pfSense requires *ATLEAST* 128 megs of ram to function correctly.\n";
1200
		echo "Only ($avail) megs of ram has been detected.\n";
1201
		echo "\nPress ENTER to continue.";
1202
		fgets($fp);
1203
		echo "\n";
1204
	}
1205

    
1206
	$iflist = get_interface_list();
1207

    
1208
	echo <<<EOD
1209

    
1210
Valid interfaces are:
1211

    
1212

    
1213
EOD;
1214

    
1215
	if(!is_array($iflist)) {
1216
		echo "No interfaces found!\n";
1217
	} else {
1218
		foreach ($iflist as $iface => $ifa) {
1219
			echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1220
				$ifa['up'] ? "   (up)" : "");
1221
		}
1222
	}
1223

    
1224
	echo <<<EOD
1225

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

    
1230
Do you want to set up VLANs now [y|n]?
1231
EOD;
1232

    
1233
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
1234
		vlan_setup();
1235

    
1236
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1237

    
1238
		echo "\n\nVLAN interfaces:\n\n";
1239
		$i = 0;
1240
		foreach ($config['vlans']['vlan'] as $vlan) {
1241

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

    
1245
			$iflist['vlan' . $i] = array();
1246
			$i++;
1247
		}
1248
	}
1249

    
1250
	echo <<<EOD
1251

    
1252
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
1253
        If you do not have two interfaces turn off the machine until
1254
	    you do.
1255

    
1256
	    And now in ENGLISH.  If you do not have atleast two *REAL*
1257
	    network interface cards or one nic with multiple VLANS then
1258
	    pfSense *WILL NOT* run correctly.
1259

    
1260
If you do not know the names of your interfaces, you may choose to use
1261
auto-detection... In that case, disconnect all interfaces now before
1262
hitting a.   The system will then prompt you to plug in each nic to
1263
autodetect.
1264

    
1265
EOD;
1266

    
1267
	do {
1268
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
1269
		$lanif = chop(fgets($fp));
1270
		if ($lanif === "") {
1271
			return;
1272
		}
1273

    
1274
		if ($lanif === "a")
1275
			$lanif = autodetect_interface("LAN", $fp);
1276
		else if (!array_key_exists($lanif, $iflist)) {
1277
			echo "\nInvalid interface name '{$lanif}'\n";
1278
			unset($lanif);
1279
			continue;
1280
		}
1281
	} while (!$lanif);
1282

    
1283
	do {
1284
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
1285
		$wanif = chop(fgets($fp));
1286
		if ($wanif === "") {
1287
			return;
1288
		}
1289
		if ($wanif === "a")
1290
			$wanif = autodetect_interface("WAN", $fp);
1291
		else if (!array_key_exists($wanif, $iflist)) {
1292
			echo "\nInvalid interface name '{$wanif}'\n";
1293
			unset($wanif);
1294
			continue;
1295
		}
1296
	} while (!$wanif);
1297

    
1298
	/* optional interfaces */
1299
	$i = 0;
1300
	$optif = array();
1301

    
1302
	while (1) {
1303
		if ($optif[$i])
1304
			$i++;
1305
		$i1 = $i + 1;
1306

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

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

    
1313
		$optif[$i] = chop(fgets($fp));
1314

    
1315
		if ($optif[$i]) {
1316
			if ($optif[$i] === "a") {
1317
				$ad = autodetect_interface("Optional " . $i1, $fp);
1318
				if ($ad)
1319
					$optif[$i] = $ad;
1320
				else
1321
					unset($optif[$i]);
1322
			} else if (!array_key_exists($optif[$i], $iflist)) {
1323
				echo "\nInvalid interface name '{$optif[$i]}'\n";
1324
				unset($optif[$i]);
1325
				continue;
1326
			}
1327
		} else {
1328
			unset($optif[$i]);
1329
			break;
1330
		}
1331
	}
1332

    
1333
	/* check for double assignments */
1334
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1335

    
1336
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1337
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1338
			if ($ifarr[$i] == $ifarr[$j]) {
1339
				echo <<<EOD
1340

    
1341
Error: you cannot assign the same interface name twice!
1342

    
1343
EOD;
1344

    
1345
				return;
1346
			}
1347
		}
1348
	}
1349

    
1350
	echo <<<EOD
1351

    
1352
The interfaces will be assigned as follows:
1353

    
1354
LAN  -> {$lanif}
1355
WAN  -> {$wanif}
1356

    
1357
EOD;
1358

    
1359
	for ($i = 0; $i < count($optif); $i++) {
1360
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1361
	}
1362

    
1363
echo <<<EOD
1364

    
1365
Do you want to proceed [y|n]?
1366
EOD;
1367

    
1368
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1369

    
1370
		$config['interfaces']['lan']['if'] = $lanif;
1371
		if (preg_match($g['wireless_regex'], $lanif)) {
1372
			if (!is_array($config['interfaces']['lan']['wireless']))
1373
				$config['interfaces']['lan']['wireless'] = array();
1374
		} else {
1375
			unset($config['interfaces']['lan']['wireless']);
1376
		}
1377

    
1378
		$config['interfaces']['wan']['if'] = $wanif;
1379
		if (preg_match($g['wireless_regex'], $wanif)) {
1380
			if (!is_array($config['interfaces']['wan']['wireless']))
1381
				$config['interfaces']['wan']['wireless'] = array();
1382
		} else {
1383
			unset($config['interfaces']['wan']['wireless']);
1384
		}
1385

    
1386
		for ($i = 0; $i < count($optif); $i++) {
1387
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1388
				$config['interfaces']['opt' . ($i+1)] = array();
1389

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

    
1392
			/* wireless interface? */
1393
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1394
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1395
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1396
			} else {
1397
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1398
			}
1399

    
1400
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1401
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1402
		}
1403

    
1404
		/* remove all other (old) optional interfaces */
1405
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1406
			unset($config['interfaces']['opt' . ($i+1)]);
1407

    
1408
		write_config();
1409

    
1410
		echo <<<EOD
1411

    
1412

    
1413

    
1414
EOD;
1415

    
1416
		if($g['booting'])
1417
			return;
1418

    
1419
		echo "One moment while we reload the settings...";
1420

    
1421
		$g['booting'] = false;
1422

    
1423
		/* resync everything */
1424
		reload_all_sync();
1425

    
1426
		echo " done!\n";
1427

    
1428
		touch("{$g['tmp_path']}/assign_complete");
1429

    
1430
	}
1431
}
1432

    
1433
function autodetect_interface($ifname, $fp) {
1434
	$iflist_prev = get_interface_list("media");
1435
	echo <<<EOD
1436

    
1437
Connect the {$ifname} interface now and make sure that the link is up.
1438
Then press ENTER to continue.
1439

    
1440
EOD;
1441
	fgets($fp);
1442
	$iflist = get_interface_list("media");
1443

    
1444
	foreach ($iflist_prev as $ifn => $ifa) {
1445
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1446
			echo "Detected link-up on interface {$ifn}.\n";
1447
			return $ifn;
1448
		}
1449
	}
1450

    
1451
	echo "No link-up detected.\n";
1452

    
1453
	return null;
1454
}
1455

    
1456
function vlan_setup() {
1457
	global $iflist, $config, $g, $fp;
1458

    
1459
	$iflist = get_interface_list();
1460

    
1461
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1462

    
1463
	echo <<<EOD
1464

    
1465
WARNING: all existing VLANs will be cleared if you proceed!
1466

    
1467
Do you want to proceed [y|n]?
1468
EOD;
1469

    
1470
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1471
		return;
1472
	}
1473

    
1474
	$config['vlans']['vlan'] = array();
1475
	echo "\n";
1476

    
1477
	while (1) {
1478
		$vlan = array();
1479

    
1480
		echo "\n\nVLAN Capable interfaces:\n\n";
1481
		if(!is_array($iflist)) {
1482
			echo "No interfaces found!\n";
1483
		} else {
1484
			$vlan_capable=0;
1485
			foreach ($iflist as $iface => $ifa) {
1486
				if (is_jumbo_capable($iface)) {
1487
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1488
						$ifa['up'] ? "   (up)" : "");
1489
					$vlan_capable++;
1490
				}
1491
			}
1492
		}
1493

    
1494
		if($vlan_capable == 0) {
1495
			echo "No VLAN capable interfaces detected.\n";
1496
			return;
1497
		}
1498

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

    
1502
		if ($vlan['if']) {
1503
			if (!array_key_exists($vlan['if'], $iflist) or
1504
			    !is_jumbo_capable($vlan['if'])) {
1505
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1506
				continue;
1507
			}
1508
		} else {
1509
			break;
1510
		}
1511

    
1512
		echo "Enter the VLAN tag (1-4094): ";
1513
		$vlan['tag'] = chop(fgets($fp));
1514

    
1515
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1516
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1517
			continue;
1518
		}
1519

    
1520
		$config['vlans']['vlan'][] = $vlan;
1521
	}
1522
}
1523

    
1524
function system_start_ftp_helpers() {
1525
	require_once("interfaces.inc");
1526
	global $config, $g;
1527

    
1528
	mwexec("/usr/bin/killall ftpsesame");
1529

    
1530
	/* build an array of interfaces to work with */
1531
	$iflist = array("lan" => "LAN");
1532
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
1533
		$iflist['opt' . $i] = "opt{$i}";
1534

    
1535
	/* loop through all interfaces and handle pftpx */
1536
	$interface_counter = 0;
1537
	foreach ($iflist as $ifent => $ifname) {
1538
		/*    if the ftp proxy is disabled for this interface then kill pftpx
1539
		 *    instance and continue. note that the helpers for port forwards are
1540
		 *    launched in a  different sequence so we are filtering them out
1541
	         *    here by not including -c {$port} -g 8021 first.
1542
		 */
1543
		 /* only install a ftp helper for enabled interfaces. wan and lan are always enabled. */
1544
		if(stristr($ifname, "opt") <> false)
1545
			if(!isset($config['interfaces'][strtolower($ifname)]['enable']))
1546
				continue;
1547
		$port = 8021 + $interface_counter;
1548
		if(isset($config['interfaces'][$ifname]['disableftpproxy'])) {
1549
			/*    item is disabled.  lets ++ the interface counter and
1550
			 *    keep processing interfaces. kill pftpx if already
1551
			 *    running for this instance.
1552
			 */
1553
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx -c {$port}\" | grep -v grep | sed \"s/  */ /g\" | cut -f2 -d\" \"");
1554
			if($helpers)
1555
				mwexec("/bin/kill {$helpers}");
1556
			$interface_counter++;
1557
		} else {
1558
			/* grab the current interface IP address */
1559
			$int = convert_friendly_interface_to_real_interface_name($ifname);
1560
			$ip = find_interface_ip($int);
1561
			/* are we in routed mode? no source nat rules and not a outside interface? */
1562
			/* If we have advanced outbound nat we skip the FTP proxy, we use ftpsesame */
1563
			if((isset($config['nat']['advancedoutbound']['enable'])) && (! interface_has_gateway($ifname))) {
1564
				$sourcenat = 0;
1565
				/* we are using advanced outbound nat, are we in routing mode? */
1566
				/* if the interface address lies within a outbound NAT source network we should skip */
1567
				if(! empty($config['nat']['advancedoutbound']['rule'])) {
1568
					foreach($config['nat']['advancedoutbound']['rule'] as $natnetwork) {
1569
						if(ip_in_subnet($ip, $natnetwork['source']['network'])) {
1570
							/* if the interface address is matched in the AON Rule we need the ftp proxy */
1571
							$sourcenat++;
1572
						}
1573
					}
1574
				}
1575
				if($sourcenat == 0) {
1576
					log_error("Config: No AON rule matched for interface {$ifname} - not using FTP proxy");
1577
					mwexec("/usr/local/sbin/ftpsesame -i $int");
1578
					$interface_counter++;
1579
					continue;
1580
				} else {
1581
					log_error("Config: AON rule matched for interface {$ifname} - using FTP proxy");
1582
				}
1583
			}
1584
			/* if pftpx is already running then do not launch it again */
1585
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx -c {$port}\" | grep -v grep | sed \"s/  */ /g\"");
1586
			if(!$helpers && $ip)
1587
 				mwexec("/usr/local/sbin/pftpx -c {$port} -g 8021 {$ip}");
1588
			if(!$ip)
1589
				mwexec("/usr/local/sbin/ftpsesame -i $int");
1590
			$interface_counter++;
1591
		}
1592
	}
1593
	/* support bridged interfaces.  even they need ftp mojo */
1594
	$num_bridges = find_number_of_created_bridges();
1595
	$num_bridges++;
1596
	for($x=0; $x<$num_bridges; $x++) {
1597
		mwexec("/usr/local/sbin/ftpsesame -i bridge{$x}");
1598
	}
1599
}
1600

    
1601
function cleanup_backupcache($revisions = 30) {
1602
	global $g;
1603
	$i = false;
1604
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1605
		conf_mount_rw();
1606
		$backups = get_backups();
1607
		$newbaks = array();
1608
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1609
		$baktimes = $backups['versions'];
1610
		$tocache = array();
1611
		unset($backups['versions']);
1612
       		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1613
				$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1614
                if(!in_array($tocheck, $baktimes)) {
1615
					$i = true;
1616
					if($g['booting'])
1617
						print " " . $tocheck . "a";
1618
					$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1619
					if($newxml['revision']['description'] == "")
1620
						$newxml['revision']['description'] = "Unknown";
1621
					$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1622
				}
1623
        	}
1624
		foreach($backups as $checkbak) {
1625
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1626
				$newbaks[] = $checkbak;
1627
			} else {
1628
				$i = true;
1629
				if($g['booting']) print " " . $tocheck . "r";
1630
			}
1631
		}
1632
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1633
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1634
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1635
			foreach($toslice as $sliced)
1636
				$newcache[$sliced] = $tocache[$sliced];
1637
			foreach($tocache as $version => $versioninfo) {
1638
				if(!in_array($version, array_keys($newcache))) {
1639
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1640
					if($g['booting']) print " " . $tocheck . "d";
1641
				}
1642
			}
1643
			$tocache = $newcache;
1644
		}
1645
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1646
        fwrite($bakout, serialize($tocache));
1647
		fclose($bakout);
1648
		conf_mount_ro();
1649
	}
1650
	if($g['booting']) {
1651
		if($i) {
1652
			print "done.\n";
1653
		}
1654
	}
1655
}
1656

    
1657
function get_backups() {
1658
	global $g;
1659
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1660
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1661
		$bakvers = array_keys($confvers);
1662
		$toreturn = array();
1663
		sort($bakvers);
1664
		// 	$bakvers = array_reverse($bakvers);
1665
		foreach(array_reverse($bakvers) as $bakver)
1666
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1667
	} else {
1668
		return false;
1669
	}
1670
	$toreturn['versions'] = $bakvers;
1671
	return $toreturn;
1672
}
1673

    
1674
function backup_config() {
1675
	global $config, $g;
1676

    
1677
	if($g['platform'] == "cdrom")
1678
		return;
1679

    
1680
	conf_mount_rw();
1681

    
1682
	/* Create backup directory if needed */
1683
	safe_mkdir("{$g['cf_conf_path']}/backup");
1684

    
1685
    if($config['revision']['time'] == "") {
1686
            $baktime = 0;
1687
    } else {
1688
            $baktime = $config['revision']['time'];
1689
    }
1690
    if($config['revision']['description'] == "") {
1691
            $bakdesc = "Unknown";
1692
    } else {
1693
            $bakdesc = $config['revision']['description'];
1694
    }
1695
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1696
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1697
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1698
    } else {
1699
            $backupcache = array();
1700
    }
1701
    $backupcache[$baktime] = array('description' => $bakdesc);
1702
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1703
    fwrite($bakout, serialize($backupcache));
1704
    fclose($bakout);
1705

    
1706
	conf_mount_ro();
1707

    
1708
	return true;
1709
}
1710

    
1711
function mute_kernel_msgs() {
1712
	exec("/sbin/conscontrol mute on");
1713
}
1714

    
1715
function unmute_kernel_msgs() {
1716
	exec("/sbin/conscontrol mute off");
1717
}
1718

    
1719
function start_devd() {
1720
	exec("/sbin/devd");
1721
	sleep(1);
1722
	if(file_exists("/tmp/rc.linkup"))
1723
		unlink("/tmp/rc.linkup");
1724
}
1725

    
1726
function set_device_perms() {
1727
	$devices = array(
1728
		'pf'	=> array(	'user'	=> 'proxy',
1729
					'group'	=> 'proxy',
1730
					'mode'	=> 0660),
1731
		);
1732

    
1733
	foreach ($devices as $name => $attr) {
1734
		$path = "/dev/$name";
1735
		if (file_exists($path)) {
1736
			chown($path, $attr['user']);
1737
			chgrp($path, $attr['group']);
1738
			chmod($path, $attr['mode']);
1739
		}
1740
	}
1741
}
1742

    
1743
if($g['booting']) echo ".";
1744
$config = parse_config();
1745

    
1746
?>
(5-5/27)