Project

General

Profile

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

    
11
	config.inc
12
	Copyright (C) 2004-2006 Scott Ullrich
13
	All rights reserved.
14

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

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

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

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

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

    
41
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

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

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

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

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

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

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

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

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

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

    
170

    
171
EOD;
172

    
173
				mwexec("/sbin/halt");
174
				exit;
175
			}
176
		}
177

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

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

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

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

    
197
if($g['booting']) echo ".";
198
$config = parse_config();
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($g['booting']) echo ".";
211
	config_lock();
212
	if(!$parse) {
213
		if(file_exists($g['tmp_path'] . '/config.cache')) {
214
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
215
			if(is_null($config)) {
216
				config_unlock();
217
				parse_config(true);
218
			}
219
		} else {
220
			config_unlock();
221
			if(!file_exists($g['conf_path'] . "/config.xml")) {
222
				log_error("No config.xml found, attempting last known config restore.");
223
				$last_backup = discover_last_backup();
224
				if ($last_backup)
225
					restore_backup("/cf/conf/backup/{$last_backup}");
226
				else
227
					log_error("Could not restore config.xml.");
228
			}
229
			$config = parse_config(true);
230
		}
231
	} else {
232
		if(!file_exists($g['conf_path'] . "/config.xml")) {
233
			if($g['booting']) echo ".";
234
			log_error("No config.xml found, attempting last known config restore.");
235
			$last_backup = discover_last_backup();
236
			if ($last_backup)
237
				restore_backup("/cf/conf/backup/{$last_backup}");
238
			else
239
				log_error("Could not restore config.xml.");
240
		}
241
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
242
		generate_config_cache($config);
243
	}
244
	if($g['booting']) echo ".";
245
	alias_make_table($config);
246
	config_unlock();
247

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

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

    
261
	return $config;
262
}
263

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

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

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

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

    
343
	parse_config(true);
344

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

    
348

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

    
357

    
358
EOD;
359
		}
360

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

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

    
376
	/* do not mount on cdrom platform */
377
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
378
		return;
379

    
380
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
381
	if($status <> 0) {
382
		if($g['booting'])
383
			echo "Disk is dirty.  Running fsck -y\n";
384
		mwexec("/sbin/fsck -y {$g['cf_path']}");
385
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
386
	}
387

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
814
	if ($prev_version != $config['version'])
815
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
816
}
817

    
818
/****f* config/write_config
819
 * NAME
820
 *   write_config - Backup and write the firewall configuration.
821
 * DESCRIPTION
822
 *   write_config() handles backing up the current configuration,
823
 *   applying changes, and regenerating the configuration cache.
824
 * INPUTS
825
 *   $desc	- string containing the a description of configuration changes
826
 *   $backup	- boolean: do not back up current configuration if false.
827
 * RESULT
828
 *   null
829
 ******/
830
/* save the system configuration */
831
function write_config($desc="Unknown", $backup = true) {
832
	global $config, $g;
833

    
834
	if($backup)
835
		backup_config();
836

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

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

    
844
	$config['revision']['description'] = $desc;
845
	$config['revision']['time'] = $changetime;
846

    
847
	config_lock();
848

    
849
	/* generate configuration XML */
850
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
851

    
852
	conf_mount_rw();
853

    
854
	/* write new configuration */
855
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
856
	if (!$fd)
857
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
858
	fwrite($fd, $xmlconfig);
859
	fclose($fd);
860

    
861
	if($g['platform'] == "embedded") {
862
		/*   backup last config.xml and remove all others to avoid
863
		 *   filling up the compact flash dedicated config partition
864
		 */
865
		$last_backup = discover_last_backup();
866
		mwexec("/bin/mv /cf/conf/backup/{$last_backup} /tmp/lastconfig.xml");
867
		mwexec("/bin/rm /cf/conf/backup/*");
868
		mwexec("/bin/mv /tmp/lastconfig.xml /cf/conf/backup/{$last_backup}");
869
	}
870

    
871
	if($g['booting'] <> true) {
872
		conf_mount_ro();
873
	}
874

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

    
878
	/* write config cache */
879
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
880
	if ($fd) {
881
		fwrite($fd, serialize($config));
882
		fclose($fd);
883
	}
884

    
885
	config_unlock();
886

    
887
	/* tell kernel to sync fs data */
888
	mwexec("/bin/sync");
889

    
890
	return $config;
891
}
892

    
893
/****f* config/reset_factory_defaults
894
 * NAME
895
 *   reset_factory_defaults - Reset the system to its default configuration.
896
 * RESULT
897
 *   integer	- indicates completion
898
 ******/
899
function reset_factory_defaults() {
900
	global $g;
901

    
902
	config_lock();
903
	conf_mount_rw();
904

    
905
	/* create conf directory, if necessary */
906
	safe_mkdir("{$g['cf_conf_path']}");
907

    
908
	/* clear out /conf */
909
	$dh = opendir($g['conf_path']);
910
	while ($filename = readdir($dh)) {
911
		if (($filename != ".") && ($filename != "..")) {
912
			unlink_if_exists($g['conf_path'] . "/" . $filename);
913
		}
914
	}
915
	closedir($dh);
916

    
917
	/* copy default configuration */
918
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
919

    
920
	/* call the wizard */
921
	touch("/conf/trigger_initial_wizard");
922

    
923
	conf_mount_ro();
924
	config_unlock();
925

    
926
	return 0;
927
}
928

    
929
function config_restore($conffile) {
930
	global $config, $g;
931

    
932
	if (!file_exists($conffile))
933
		return 1;
934

    
935
    config_lock();
936
    conf_mount_rw();
937

    
938
    backup_config();
939
    copy($conffile, "{$g['cf_conf_path']}/config.xml");
940
	$config = parse_config(true);
941
    write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
942

    
943
    conf_mount_ro();
944
    config_unlock();
945

    
946
    return 0;
947
}
948

    
949
function config_install($conffile) {
950
	global $config, $g;
951

    
952
	if (!file_exists($conffile))
953
		return 1;
954

    
955
	if (!config_validate("{$g['conf_path']}/config.xml"))
956
		return 1;
957

    
958
	if($g['booting'] == true)
959
		echo "Installing configuration...\n";
960

    
961
    config_lock();
962
    conf_mount_rw();
963

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

    
966
	/* unlink cache file if it exists */
967
	if(file_exists("{$g['tmp_path']}/config.cache"))
968
		unlink("{$g['tmp_path']}/config.cache");
969

    
970
    conf_mount_ro();
971
    config_unlock();
972

    
973
    return 0;
974
}
975

    
976
function config_validate($conffile) {
977

    
978
	global $g, $xmlerr;
979

    
980
	$xml_parser = xml_parser_create();
981

    
982
	if (!($fp = fopen($conffile, "r"))) {
983
		$xmlerr = "XML error: unable to open file";
984
		return false;
985
	}
986

    
987
	while ($data = fread($fp, 4096)) {
988
		if (!xml_parse($xml_parser, $data, feof($fp))) {
989
			$xmlerr = sprintf("%s at line %d",
990
						xml_error_string(xml_get_error_code($xml_parser)),
991
						xml_get_current_line_number($xml_parser));
992
			return false;
993
		}
994
	}
995
	xml_parser_free($xml_parser);
996

    
997
	fclose($fp);
998

    
999
	return true;
1000
}
1001

    
1002
/*   lock configuration file, decide that the lock file
1003
 *   is stale after 10 seconds
1004
 */
1005
function config_lock() {
1006
	global $g, $process_lock;
1007

    
1008
	/* No need to continue if we're the ones holding the lock */
1009
	if ($process_lock)
1010
		return;
1011

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

    
1014
	$n = 0;
1015
	while ($n < 10) {
1016
		/* open the lock file in append mode to avoid race condition */
1017
		if ($fd = @fopen($lockfile, "x")) {
1018
			/* succeeded */
1019
			$process_lock = true;
1020
			fclose($fd);
1021
			return;
1022
		} else {
1023
			/* file locked, wait and try again */
1024
			$process_lock = false;
1025
			sleep(1);
1026
			$n++;
1027
		}
1028
	}
1029
}
1030

    
1031
/* unlock configuration file */
1032
function config_unlock() {
1033
	global $g, $process_lock;
1034

    
1035
	$lockfile = "{$g['varrun_path']}/config.lock";
1036
	$process_lock = false;
1037

    
1038
	unlink_if_exists($lockfile);
1039
}
1040

    
1041
function set_networking_interfaces_ports() {
1042
	global $noreboot;
1043
	global $config;
1044
	global $g;
1045
	global $fp;
1046

    
1047
	$fp = fopen('php://stdin', 'r');
1048

    
1049
	$iflist = get_interface_list();
1050

    
1051
	echo <<<EOD
1052

    
1053
Valid interfaces are:
1054

    
1055

    
1056
EOD;
1057

    
1058
	if(!is_array($iflist)) {
1059
		echo "No interfaces found!\n";
1060
	} else {
1061
		foreach ($iflist as $iface => $ifa) {
1062
			echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1063
				$ifa['up'] ? "   (up)" : "");
1064
		}
1065
	}
1066

    
1067
	echo <<<EOD
1068

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

    
1073
Do you want to set up VLANs now [y|n]?
1074
EOD;
1075

    
1076
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
1077
		vlan_setup();
1078

    
1079
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1080

    
1081
		echo "\n\nVLAN interfaces:\n\n";
1082
		$i = 0;
1083
		foreach ($config['vlans']['vlan'] as $vlan) {
1084

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

    
1088
			$iflist['vlan' . $i] = array();
1089
			$i++;
1090
		}
1091
	}
1092

    
1093
	echo <<<EOD
1094

    
1095
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
1096
        If you do not have two interfaces turn off the machine until
1097
	you do.
1098

    
1099
If you do not know the names of your interfaces, you may choose to use
1100
auto-detection... In that case, disconnect all interfaces now before
1101
hitting a.   The system will then prompt you to plug in each nic to
1102
autodetect.
1103

    
1104
EOD;
1105

    
1106
	do {
1107
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
1108
		$lanif = chop(fgets($fp));
1109
		if ($lanif === "") {
1110
			return;
1111
		}
1112

    
1113
		if ($lanif === "a")
1114
			$lanif = autodetect_interface("LAN", $fp);
1115
		else if (!array_key_exists($lanif, $iflist)) {
1116
			echo "\nInvalid interface name '{$lanif}'\n";
1117
			unset($lanif);
1118
			continue;
1119
		}
1120
	} while (!$lanif);
1121

    
1122
	do {
1123
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
1124
		$wanif = chop(fgets($fp));
1125
		if ($wanif === "") {
1126
			return;
1127
		}
1128
		if ($wanif === "a")
1129
			$wanif = autodetect_interface("WAN", $fp);
1130
		else if (!array_key_exists($wanif, $iflist)) {
1131
			echo "\nInvalid interface name '{$wanif}'\n";
1132
			unset($wanif);
1133
			continue;
1134
		}
1135
	} while (!$wanif);
1136

    
1137
	/* optional interfaces */
1138
	$i = 0;
1139
	$optif = array();
1140

    
1141
	while (1) {
1142
		if ($optif[$i])
1143
			$i++;
1144
		$i1 = $i + 1;
1145

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

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

    
1152
		$optif[$i] = chop(fgets($fp));
1153

    
1154
		if ($optif[$i]) {
1155
			if ($optif[$i] === "a") {
1156
				$ad = autodetect_interface("Optional " . $i1, $fp);
1157
				if ($ad)
1158
					$optif[$i] = $ad;
1159
				else
1160
					unset($optif[$i]);
1161
			} else if (!array_key_exists($optif[$i], $iflist)) {
1162
				echo "\nInvalid interface name '{$optif[$i]}'\n";
1163
				unset($optif[$i]);
1164
				continue;
1165
			}
1166
		} else {
1167
			unset($optif[$i]);
1168
			break;
1169
		}
1170
	}
1171

    
1172
	/* check for double assignments */
1173
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1174

    
1175
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1176
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1177
			if ($ifarr[$i] == $ifarr[$j]) {
1178
				echo <<<EOD
1179

    
1180
Error: you cannot assign the same interface name twice!
1181

    
1182
EOD;
1183

    
1184
				return;
1185
			}
1186
		}
1187
	}
1188

    
1189
	echo <<<EOD
1190

    
1191
The interfaces will be assigned as follows:
1192

    
1193
LAN  -> {$lanif}
1194
WAN  -> {$wanif}
1195

    
1196
EOD;
1197

    
1198
	for ($i = 0; $i < count($optif); $i++) {
1199
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1200
	}
1201

    
1202
echo <<<EOD
1203

    
1204
Do you want to proceed [y|n]?
1205
EOD;
1206

    
1207
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1208

    
1209
		$config['interfaces']['lan']['if'] = $lanif;
1210
		if (preg_match($g['wireless_regex'], $lanif)) {
1211
			if (!is_array($config['interfaces']['lan']['wireless']))
1212
				$config['interfaces']['lan']['wireless'] = array();
1213
		} else {
1214
			unset($config['interfaces']['lan']['wireless']);
1215
		}
1216

    
1217
		$config['interfaces']['wan']['if'] = $wanif;
1218
		if (preg_match($g['wireless_regex'], $wanif)) {
1219
			if (!is_array($config['interfaces']['wan']['wireless']))
1220
				$config['interfaces']['wan']['wireless'] = array();
1221
		} else {
1222
			unset($config['interfaces']['wan']['wireless']);
1223
		}
1224

    
1225
		for ($i = 0; $i < count($optif); $i++) {
1226
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1227
				$config['interfaces']['opt' . ($i+1)] = array();
1228

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

    
1231
			/* wireless interface? */
1232
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1233
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1234
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1235
			} else {
1236
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1237
			}
1238

    
1239
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1240
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1241
		}
1242

    
1243
		/* remove all other (old) optional interfaces */
1244
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1245
			unset($config['interfaces']['opt' . ($i+1)]);
1246

    
1247
		write_config();
1248

    
1249
		echo <<<EOD
1250

    
1251

    
1252

    
1253
EOD;
1254

    
1255
		if($g['booting'])
1256
			return;
1257

    
1258
		echo "One moment while we reload the settings...";
1259

    
1260
		$g['booting'] = false;
1261

    
1262
		/* resync everything */
1263
		reload_all_sync();
1264

    
1265
		echo " done!\n";
1266

    
1267
		touch("{$g['tmp_path']}/assign_complete");
1268

    
1269
	}
1270
}
1271

    
1272
function autodetect_interface($ifname, $fp) {
1273
	$iflist_prev = get_interface_list("media");
1274
	echo <<<EOD
1275

    
1276
Connect the {$ifname} interface now and make sure that the link is up.
1277
Then press ENTER to continue.
1278

    
1279
EOD;
1280
	fgets($fp);
1281
	$iflist = get_interface_list("media");
1282

    
1283
	foreach ($iflist_prev as $ifn => $ifa) {
1284
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1285
			echo "Detected link-up on interface {$ifn}.\n";
1286
			return $ifn;
1287
		}
1288
	}
1289

    
1290
	echo "No link-up detected.\n";
1291

    
1292
	return null;
1293
}
1294

    
1295
function vlan_setup() {
1296
	global $iflist, $config, $g, $fp;
1297

    
1298
	$iflist = get_interface_list();
1299

    
1300
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1301

    
1302
	echo <<<EOD
1303

    
1304
WARNING: all existing VLANs will be cleared if you proceed!
1305

    
1306
Do you want to proceed [y|n]?
1307
EOD;
1308

    
1309
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1310
		return;
1311
	}
1312

    
1313
	$config['vlans']['vlan'] = array();
1314
	echo "\n";
1315

    
1316
	while (1) {
1317
		$vlan = array();
1318

    
1319
		echo "\n\nVLAN Capable interfaces:\n\n";
1320
		if(!is_array($iflist)) {
1321
			echo "No interfaces found!\n";
1322
		} else {
1323
			$vlan_capable=0;
1324
			foreach ($iflist as $iface => $ifa) {
1325
				if (is_jumbo_capable($iface)) {
1326
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1327
						$ifa['up'] ? "   (up)" : "");
1328
					$vlan_capable++;
1329
				}
1330
			}
1331
		}
1332

    
1333
		if($vlan_capable == 0) {
1334
			echo "No VLAN capable interfaces detected.\n";
1335
			return;
1336
		}
1337

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

    
1341
		if ($vlan['if']) {
1342
			if (!array_key_exists($vlan['if'], $iflist) or
1343
			    !is_jumbo_capable($vlan['if'])) {
1344
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1345
				continue;
1346
			}
1347
		} else {
1348
			break;
1349
		}
1350

    
1351
		echo "Enter the VLAN tag (1-4094): ";
1352
		$vlan['tag'] = chop(fgets($fp));
1353

    
1354
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1355
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1356
			continue;
1357
		}
1358

    
1359
		$config['vlans']['vlan'][] = $vlan;
1360
	}
1361
}
1362

    
1363
function system_start_ftp_helpers() {
1364
	require_once("interfaces.inc");
1365
	global $config, $g;
1366

    
1367
	mwexec("/usr/bin/killall ftpsesame");
1368

    
1369
	/* build an array of interfaces to work with */
1370
	$iflist = array("lan" => "LAN");
1371
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
1372
		$iflist['opt' . $i] = "opt{$i}";
1373

    
1374
	/* loop through all interfaces and handle pftpx */
1375
	$interface_counter = 0;
1376
	foreach ($iflist as $ifent => $ifname) {
1377
		/*    if the ftp proxy is disabled for this interface then kill pftpx
1378
		 *    instance and continue. note that the helpers for port forwards are
1379
		 *    launched in a  different sequence so we are filtering them out
1380
         *    here by not including -c {$port} -g 8021 first.
1381
		 */
1382
		 /* only install a ftp helper for enabled interfaces. wan and lan are always enabled. */
1383
		if(stristr($ifname, "opt") <> false)
1384
			if(!isset($config['interfaces'][strtolower($ifname)]['enable']))
1385
				continue;
1386
		$port = 8021 + $interface_counter;
1387
		if(isset($config['interfaces'][$ifname]['disableftpproxy'])) {
1388
			/*    item is disabled.  lets ++ the interface counter and
1389
			 *    keep processing interfaces. kill pftpx if already
1390
			 *    running for this instance.
1391
			 */
1392
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx -c {$port}\" | grep -v grep | sed \"s/  */ /g\" | cut -f2 -d\" \"");
1393
			if($helpers)
1394
				mwexec("/bin/kill {$helpers}");
1395
			$interface_counter++;
1396
		} else {
1397
			/* grab the current interface IP address */
1398
			$int = convert_friendly_interface_to_real_interface_name($ifname);
1399
			$ip = find_interface_ip($int);
1400
			/* if pftpx is already running then do not launch it again */
1401
			$helpers = exec("/bin/ps awux | grep \"/usr/local/sbin/pftpx -c {$port}\" | grep -v grep | sed \"s/  */ /g\"");
1402
			if(!$helpers && $ip)
1403
 				mwexec("/usr/local/sbin/pftpx -c {$port} -g 8021 {$ip}");
1404
			if(!$ip)
1405
				mwexec("/usr/local/sbin/ftpsesame -i $int");
1406
			$interface_counter++;
1407
		}
1408
	}
1409
	/* support bridged interfaces.  even they need ftp mojo */
1410
	$num_bridges = find_number_of_created_bridges();
1411
	$num_bridges++;
1412
	for($x=0; $x<$num_bridges; $x++) {
1413
		mwexec("/usr/local/sbin/ftpsesame -i bridge{$x}");
1414
	}
1415
}
1416

    
1417
function cleanup_backupcache($revisions = 30) {
1418
	global $g;
1419
	$i = false;
1420
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1421
		conf_mount_rw();
1422
		$backups = get_backups();
1423
		$newbaks = array();
1424
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1425
		$baktimes = $backups['versions'];
1426
		$tocache = array();
1427
		unset($backups['versions']);
1428
       		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1429
				$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1430
                if(!in_array($tocheck, $baktimes)) {
1431
					$i = true;
1432
					if($g['booting'])
1433
						print " " . $tocheck . "a";
1434
					$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1435
					if($newxml['revision']['description'] == "")
1436
						$newxml['revision']['description'] = "Unknown";
1437
					$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1438
				}
1439
        	}
1440
		foreach($backups as $checkbak) {
1441
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1442
				$newbaks[] = $checkbak;
1443
			} else {
1444
				$i = true;
1445
				if($g['booting']) print " " . $tocheck . "r";
1446
			}
1447
		}
1448
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1449
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1450
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1451
			foreach($toslice as $sliced)
1452
				$newcache[$sliced] = $tocache[$sliced];
1453
			foreach($tocache as $version => $versioninfo) {
1454
				if(!in_array($version, array_keys($newcache))) {
1455
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1456
					if($g['booting']) print " " . $tocheck . "d";
1457
				}
1458
			}
1459
			$tocache = $newcache;
1460
		}
1461
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1462
        fwrite($bakout, serialize($tocache));
1463
		fclose($bakout);
1464
		conf_mount_ro();
1465
	}
1466
	if($g['booting']) {
1467
		if($i) {
1468
			print "done.\n";
1469
		}
1470
	}
1471
}
1472

    
1473
function get_backups() {
1474
	global $g;
1475
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1476
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1477
		$bakvers = array_keys($confvers);
1478
		$toreturn = array();
1479
		sort($bakvers);
1480
		// 	$bakvers = array_reverse($bakvers);
1481
		foreach(array_reverse($bakvers) as $bakver)
1482
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1483
	} else {
1484
		return false;
1485
	}
1486
	$toreturn['versions'] = $bakvers;
1487
	return $toreturn;
1488
}
1489

    
1490
function backup_config() {
1491
	global $config, $g;
1492

    
1493
	if($g['platform'] == "cdrom")
1494
		return;
1495

    
1496
	conf_mount_rw();
1497

    
1498
	/* Create backup directory if needed */
1499
	safe_mkdir("{$g['cf_conf_path']}/backup");
1500

    
1501
    if($config['revision']['time'] == "") {
1502
            $baktime = 0;
1503
    } else {
1504
            $baktime = $config['revision']['time'];
1505
    }
1506
    if($config['revision']['description'] == "") {
1507
            $bakdesc = "Unknown";
1508
    } else {
1509
            $bakdesc = $config['revision']['description'];
1510
    }
1511
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1512
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1513
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1514
    } else {
1515
            $backupcache = array();
1516
    }
1517
    $backupcache[$baktime] = array('description' => $bakdesc);
1518
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1519
    fwrite($bakout, serialize($backupcache));
1520
    fclose($bakout);
1521

    
1522
	conf_mount_ro();
1523

    
1524
	return true;
1525
}
1526

    
1527
function mute_kernel_msgs() {
1528
	exec("/sbin/conscontrol mute on");
1529
}
1530

    
1531
function unmute_kernel_msgs() {
1532
	exec("/sbin/conscontrol mute off");
1533
}
1534

    
1535
function start_devd() {
1536
	exec("/sbin/devd");
1537
	sleep(1);
1538
	if(file_exists("/tmp/rc.linkup"))
1539
		unlink("/tmp/rc.linkup");
1540
}
1541

    
1542
function set_device_perms() {
1543
	$devices = array(
1544
		'pf'	=> array(	'user'	=> 'proxy',
1545
					'group'	=> 'proxy',
1546
					'mode'	=> 0660),
1547
		);
1548

    
1549
	foreach ($devices as $name => $attr) {
1550
		$path = "/dev/$name";
1551
		if (file_exists($path)) {
1552
			chown($path, $attr['user']);
1553
			chgrp($path, $attr['group']);
1554
			chmod($path, $attr['mode']);
1555
		}
1556
	}
1557
}
1558

    
1559
?>
(5-5/27)