Project

General

Profile

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

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

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

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

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

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

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

    
41
if($g['booting']) echo ".";
42

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

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

    
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
		/* user has just upgraded to m0n0wall, replace root xml tags */
78
		log_error("Upgrading m0n0wall configuration to pfSense... ");
79
		$config_contents = str_replace("m0n0wall","pfsense", $config_contents);
80
		if (!config_validate("{$g['conf_path']}/config.xml"))
81
			log_error("ERROR!  Could not convert m0n0wall -> pfsense in config.xml");
82
		conf_mount_rw();
83
		$fd = fopen("/cf/conf/config.xml", "w");
84
		fwrite($fd, $config_contents);
85
		fclose($fd);
86
		conf_mount_ro();
87
	}
88
}
89

    
90
/* if our config file exists bail out, we're already set. */
91
if ($g['booting'] and !file_exists($g['cf_conf_path'] . "/config.xml")  ) {
92
	if($g['booting']) echo ".";
93
	/* find the device where config.xml resides and write out an fstab */
94
	unset($cfgdevice);
95

    
96
	/* check if there's already an fstab (NFS booting?) */
97
	if (!file_exists("{$g['etc_path']}/fstab")) {
98

    
99
		if (strstr($g['platform'], "cdrom")) {
100
			/* config is on floppy disk for CD-ROM version */
101
			$cfgdevice = $cfgpartition = "fd0";
102
			$dmesg = `dmesg -a`;
103
			if(ereg("da0", $dmesg) == true) {
104
				$cfgdevice = $cfgpartition = "da0" ;
105
				if (mwexec("/sbin/mount -r /dev/{$cfgdevice} /cf")) {
106
					/* could not mount, fallback to floppy */
107
					$cfgdevice = $cfgpartition = "fd0";
108
				}
109
			}
110
			$cfgfstype = "msdos";
111
			echo "CDROM build\n";
112
			echo "   CFG: {$cfgpartition}\n";
113
			echo "  TYPE: {$cfgfstype}\n";
114
		} else {
115
			if($g['booting']) echo ".";
116
			/* probe kernel known disks until we find one with config.xml */
117
			$disks = explode(" ", trim(preg_replace("/kern.disks: /", "", exec("/sbin/sysctl kern.disks"))));
118
			foreach ($disks as $mountdisk) {
119
				/* skip mfs mounted filesystems */
120
				if (strstr($mountdisk, "md"))
121
					continue;
122
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}a {$g['cf_path']}") == 0) {
123
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
124
						/* found it */
125
						$cfgdevice = $mountdisk;
126
						$cfgpartition = $cfgdevice . "a";
127
						$cfgfstype = "ufs";
128
						echo "Found configuration on $cfgdevice.\n";
129
					}
130

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

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

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

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

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

    
168

    
169
EOD;
170

    
171
				mwexec("/sbin/halt");
172
				exit;
173
			}
174
		}
175

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

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

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

    
187
		fwrite($fd, $fstab);
188
		fclose($fd);
189
	}
190

    
191
	/* mount all filesystems */
192
	mwexec("/sbin/mount -a");
193
}
194

    
195
if($g['booting']) echo ".";
196
$config = parse_config();
197

    
198
/****f* config/parse_config
199
 * NAME
200
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
201
 * INPUTS
202
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
203
 * RESULT
204
 *   $config      - array containing all configuration variables
205
 ******/
206
function parse_config($parse = false) {
207
	global $g;
208

    
209
	config_lock();
210
	if(!$parse) {
211
		if(file_exists($g['tmp_path'] . '/config.cache')) {
212
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
213
			if(is_null($config)) {
214
				config_unlock();
215
				parse_config(true);
216
			}
217
		} else {
218
			config_unlock();
219
			if(!file_exists($g['conf_path'] . "/config.xml")) {
220
				log_error("No config.xml found, attempting last known config restore.");
221
				$last_backup = discover_last_backup();
222
				if ($last_backup)
223
					restore_backup("/cf/conf/backup/{$last_backup}");
224
				else
225
					log_error("Could not restore config.xml.");
226
			}
227
			$config = parse_config(true);
228
		}
229
	} else {
230
		if(!file_exists($g['conf_path'] . "/config.xml")) {
231
			log_error("No config.xml found, attempting last known config restore.");
232
			$last_backup = discover_last_backup();
233
			if ($last_backup)
234
				restore_backup("/cf/conf/backup/{$last_backup}");
235
			else
236
				log_error("Could not restore config.xml.");
237
		}
238
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
239
		generate_config_cache($config);
240
	}
241

    
242
	alias_make_table($config);
243
	config_unlock();
244

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

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

    
258
	return $config;
259
}
260

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

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

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

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

    
339
	parse_config(true);
340

    
341
	if ((float)$config['version'] > (float)$g['latest_config']) {
342
		echo <<<EOD
343

    
344

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

    
353

    
354
EOD;
355
		}
356

    
357
	/* make alias table (for faster lookups) */
358
	alias_make_table($config);
359
	config_unlock();
360
}
361

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

    
372
	/* do not mount on cdrom platform */
373
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
374
		return;
375

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

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

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

    
408
	if($g['booting'] == true)
409
		return;
410

    
411
	/* do not umount if generating ssh keys */
412
	if(file_exists("/tmp/keys_generating"))
413
		return;
414

    
415
	/* do not umount on cdrom or pfSense platforms */
416
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
417
		return;
418

    
419
	/* sync data, then force a remount of /cf */
420
	mwexec("/bin/sync");
421
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
422
	mwexec("/sbin/mount -u -r -f /");
423
}
424

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

    
440
	if ($config['version'] == $g['latest_config'])
441
		return;		/* already at latest version */
442

    
443
	// Save off config version
444
	$prev_version = $config['version'];
445

    
446
	/* convert 1.0 -> 1.1 */
447
	if ($config['version'] == "1.0") {
448
		$opti = 1;
449
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
450

    
451
		/* convert DMZ to optional, if necessary */
452
		if (isset($config['interfaces']['dmz'])) {
453

    
454
			$dmzcfg = &$config['interfaces']['dmz'];
455

    
456
			if ($dmzcfg['if']) {
457
				$config['interfaces']['opt' . $opti] = array();
458
				$optcfg = &$config['interfaces']['opt' . $opti];
459

    
460
				$optcfg['enable'] = $dmzcfg['enable'];
461
				$optcfg['descr'] = "DMZ";
462
				$optcfg['if'] = $dmzcfg['if'];
463
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
464
				$optcfg['subnet'] = $dmzcfg['subnet'];
465

    
466
				$ifmap['dmz'] = "opt" . $opti;
467
				$opti++;
468
			}
469

    
470
			unset($config['interfaces']['dmz']);
471
		}
472

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

    
476
			if (!$config['interfaces']['wlan' . $i]['if']) {
477
				unset($config['interfaces']['wlan' . $i]);
478
				continue;
479
			}
480

    
481
			$wlancfg = &$config['interfaces']['wlan' . $i];
482
			$config['interfaces']['opt' . $opti] = array();
483
			$optcfg = &$config['interfaces']['opt' . $opti];
484

    
485
			$optcfg['enable'] = $wlancfg['enable'];
486
			$optcfg['descr'] = "WLAN" . $i;
487
			$optcfg['if'] = $wlancfg['if'];
488
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
489
			$optcfg['subnet'] = $wlancfg['subnet'];
490
			$optcfg['bridge'] = $wlancfg['bridge'];
491

    
492
			$optcfg['wireless'] = array();
493
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
494
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
495
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
496
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
497

    
498
			$ifmap['wlan' . $i] = "opt" . $opti;
499

    
500
			unset($config['interfaces']['wlan' . $i]);
501
			$opti++;
502
		}
503

    
504
		/* convert filter rules */
505
		$n = count($config['filter']['rule']);
506
		for ($i = 0; $i < $n; $i++) {
507

    
508
			$fr = &$config['filter']['rule'][$i];
509

    
510
			/* remap interface */
511
			if (array_key_exists($fr['interface'], $ifmap))
512
				$fr['interface'] = $ifmap[$fr['interface']];
513
			else {
514
				/* remove the rule */
515
				echo "\nWarning: filter rule removed " .
516
					"(interface '{$fr['interface']}' does not exist anymore).";
517
				unset($config['filter']['rule'][$i]);
518
				continue;
519
			}
520

    
521
			/* remap source network */
522
			if (isset($fr['source']['network'])) {
523
				if (array_key_exists($fr['source']['network'], $ifmap))
524
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
525
				else {
526
					/* remove the rule */
527
					echo "\nWarning: filter rule removed " .
528
						"(source network '{$fr['source']['network']}' does not exist anymore).";
529
					unset($config['filter']['rule'][$i]);
530
					continue;
531
				}
532
			}
533

    
534
			/* remap destination network */
535
			if (isset($fr['destination']['network'])) {
536
				if (array_key_exists($fr['destination']['network'], $ifmap))
537
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
538
				else {
539
					/* remove the rule */
540
					echo "\nWarning: filter rule removed " .
541
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
542
					unset($config['filter']['rule'][$i]);
543
					continue;
544
				}
545
			}
546
		}
547

    
548
		/* convert shaper rules */
549
		$n = count($config['pfqueueing']['rule']);
550
		if (is_array($config['pfqueueing']['rule']))
551
			for ($i = 0; $i < $n; $i++) {
552

    
553
			$fr = &$config['pfqueueing']['rule'][$i];
554

    
555
			/* remap interface */
556
			if (array_key_exists($fr['interface'], $ifmap))
557
				$fr['interface'] = $ifmap[$fr['interface']];
558
			else {
559
				/* remove the rule */
560
				echo "\nWarning: traffic shaper rule removed " .
561
					"(interface '{$fr['interface']}' does not exist anymore).";
562
				unset($config['pfqueueing']['rule'][$i]);
563
				continue;
564
			}
565

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

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

    
593
		$config['version'] = "1.1";
594
	}
595

    
596
	/* convert 1.1 -> 1.2 */
597
	if ($config['version'] == "1.1") {
598
		/* move LAN DHCP server config */
599
		$tmp = $config['dhcpd'];
600
		$config['dhcpd'] = array();
601
		$config['dhcpd']['lan'] = $tmp;
602

    
603
		/* encrypt password */
604
		$config['system']['password'] = crypt($config['system']['password']);
605

    
606
		$config['version'] = "1.2";
607
	}
608

    
609
	/* convert 1.2 -> 1.3 */
610
	if ($config['version'] == "1.2") {
611
		/* convert advanced outbound NAT config */
612
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
613
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
614
			$src = $curent['source'];
615
			$curent['source'] = array();
616
			$curent['source']['network'] = $src;
617
			$curent['destination'] = array();
618
			$curent['destination']['any'] = true;
619
		}
620

    
621
		/* add an explicit type="pass" to all filter rules to make things consistent */
622
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
623
			$config['filter']['rule'][$i]['type'] = "pass";
624
		}
625

    
626
		$config['version'] = "1.3";
627
	}
628

    
629
	/* convert 1.3 -> 1.4 */
630
	if ($config['version'] == "1.3") {
631
		/* convert shaper rules (make pipes) */
632
		if (is_array($config['pfqueueing']['rule'])) {
633
			$config['pfqueueing']['pipe'] = array();
634

    
635
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
636
				$curent = &$config['pfqueueing']['rule'][$i];
637

    
638
				/* make new pipe and associate with this rule */
639
				$newpipe = array();
640
				$newpipe['descr'] = $curent['descr'];
641
				$newpipe['bandwidth'] = $curent['bandwidth'];
642
				$newpipe['delay'] = $curent['delay'];
643
				$newpipe['mask'] = $curent['mask'];
644
				$config['pfqueueing']['pipe'][$i] = $newpipe;
645

    
646
				$curent['targetpipe'] = $i;
647

    
648
				unset($curent['bandwidth']);
649
				unset($curent['delay']);
650
				unset($curent['mask']);
651
			}
652
		}
653

    
654
		$config['version'] = "1.4";
655
	}
656

    
657
	/* Convert 1.4 -> 1.5 */
658
	if ($config['version'] == "1.4") {
659

    
660
		/* Default route moved */
661
		if (isset($config['interfaces']['wan']['gateway']))
662
			if ($config['interfaces']['wan']['gateway'] <> "")
663
				$config['interfaces']['wan']['gateway'] = $config['interfaces']['wan']['gateway'];
664
		unset($config['interfaces']['wan']['gateway']);
665

    
666
                /* Queues are no longer interface specific */
667
                if (isset($config['interfaces']['lan']['schedulertype']))
668
                        unset($config['interfaces']['lan']['schedulertype']);
669
                if (isset($config['interfaces']['wan']['schedulertype']))
670
                        unset($config['interfaces']['wan']['schedulertype']);
671

    
672
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
673
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
674
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
675
                }
676

    
677
		$config['version'] = "1.5";
678
	}
679

    
680
	/* Convert 1.5 -> 1.6 */
681
	if ($config['version'] == "1.5") {
682
		/* Alternate firmware URL moved */
683
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
684
			$config['system']['alt_firmware_url'] = array();
685
			$config['system']['alt_firmware_url']['enabled'] = "";
686
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
687
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
688
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
689
		} else {
690
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
691
		}
692

    
693
		$config['version'] = "1.6";
694
	}
695

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

    
755
		/* enable SSH */
756
		if ($config['version'] == "1.8") {
757
			$config['system']['sshenabled'] = true;
758
		}
759

    
760
		$config['version'] = "1.9";
761
	}
762

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

    
806
	if ($prev_version != $config['version'])
807
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
808
}
809

    
810
/****f* config/write_config
811
 * NAME
812
 *   write_config - Backup and write the firewall configuration.
813
 * DESCRIPTION
814
 *   write_config() handles backing up the current configuration,
815
 *   applying changes, and regenerating the configuration cache.
816
 * INPUTS
817
 *   $desc	- string containing the a description of configuration changes
818
 *   $backup	- boolean: do not back up current configuration if false.
819
 * RESULT
820
 *   null
821
 ******/
822
/* save the system configuration */
823
function write_config($desc="Unknown", $backup = true) {
824
	global $config, $g;
825

    
826
	if($backup)
827
		backup_config();
828

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

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

    
836
	$config['revision']['description'] = $desc;
837
	$config['revision']['time'] = $changetime;
838

    
839
	config_lock();
840

    
841
	/* generate configuration XML */
842
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
843

    
844
	conf_mount_rw();
845

    
846
	/* write new configuration */
847
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
848
	if (!$fd)
849
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
850
	fwrite($fd, $xmlconfig);
851
	fclose($fd);
852

    
853
	if($g['platform'] == "embedded") {
854
		/*   backup last config.xml and remove all others to avoid
855
		 *   filling up the compact flash dedicated config partition
856
		 */
857
		$last_backup = discover_last_backup();
858
		mwexec("/bin/mv /cf/conf/backup/{$last_backup} /tmp/lastconfig.xml");
859
		mwexec("/bin/rm /cf/conf/backup/*");
860
		mwexec("/bin/mv /tmp/lastconfig.xml /cf/conf/backup/{$last_backup}");
861
	}
862

    
863
	if($g['booting'] <> true) {
864
		conf_mount_ro();
865
	}
866

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

    
870
	/* write config cache */
871
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
872
	if ($fd) {
873
		fwrite($fd, serialize($config));
874
		fclose($fd);
875
	}
876

    
877
	config_unlock();
878

    
879
	/* tell kernel to sync fs data */
880
	mwexec("/bin/sync");
881

    
882
	return $config;
883
}
884

    
885
/****f* config/reset_factory_defaults
886
 * NAME
887
 *   reset_factory_defaults - Reset the system to its default configuration.
888
 * RESULT
889
 *   integer	- indicates completion
890
 ******/
891
function reset_factory_defaults() {
892
	global $g;
893

    
894
	config_lock();
895
	conf_mount_rw();
896

    
897
	/* create conf directory, if necessary */
898
	safe_mkdir("{$g['cf_conf_path']}");
899

    
900
	/* clear out /conf */
901
	$dh = opendir($g['conf_path']);
902
	while ($filename = readdir($dh)) {
903
		if (($filename != ".") && ($filename != "..")) {
904
			unlink_if_exists($g['conf_path'] . "/" . $filename);
905
		}
906
	}
907
	closedir($dh);
908

    
909
	/* copy default configuration */
910
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
911

    
912
	/* call the wizard */
913
	touch("/conf/trigger_initial_wizard");
914

    
915
	conf_mount_ro();
916
	config_unlock();
917

    
918
	return 0;
919
}
920

    
921
function config_restore($conffile) {
922
	global $config, $g;
923

    
924
	if (!file_exists($conffile))
925
		return 1;
926

    
927
    config_lock();
928
    conf_mount_rw();
929

    
930
    backup_config();
931
    copy($conffile, "{$g['cf_conf_path']}/config.xml");
932
	$config = parse_config(true);
933
    write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
934

    
935
    conf_mount_ro();
936
    config_unlock();
937

    
938
    return 0;
939
}
940

    
941
function config_install($conffile) {
942
	global $config, $g;
943

    
944
	if (!file_exists($conffile))
945
		return 1;
946

    
947
	if (!config_validate("{$g['conf_path']}/config.xml"))
948
		return 1;
949

    
950
	if($g['booting'] == true)
951
		echo "Installing configuration...\n";
952

    
953
    config_lock();
954
    conf_mount_rw();
955

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

    
958
	/* unlink cache file if it exists */
959
	if(file_exists("{$g['tmp_path']}/config.cache"))
960
		unlink("{$g['tmp_path']}/config.cache");
961

    
962
    conf_mount_ro();
963
    config_unlock();
964

    
965
    return 0;
966
}
967

    
968
function config_validate($conffile) {
969

    
970
	global $g, $xmlerr;
971

    
972
	$xml_parser = xml_parser_create();
973

    
974
	if (!($fp = fopen($conffile, "r"))) {
975
		$xmlerr = "XML error: unable to open file";
976
		return false;
977
	}
978

    
979
	while ($data = fread($fp, 4096)) {
980
		if (!xml_parse($xml_parser, $data, feof($fp))) {
981
			$xmlerr = sprintf("%s at line %d",
982
						xml_error_string(xml_get_error_code($xml_parser)),
983
						xml_get_current_line_number($xml_parser));
984
			return false;
985
		}
986
	}
987
	xml_parser_free($xml_parser);
988

    
989
	fclose($fp);
990

    
991
	return true;
992
}
993

    
994
/*   lock configuration file, decide that the lock file
995
 *   is stale after 10 seconds
996
 */
997
function config_lock() {
998
	global $g, $process_lock;
999

    
1000
	/* No need to continue if we're the ones holding the lock */
1001
	if ($process_lock)
1002
		return;
1003

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

    
1006
	$n = 0;
1007
	while ($n < 10) {
1008
		/* open the lock file in append mode to avoid race condition */
1009
		if ($fd = @fopen($lockfile, "x")) {
1010
			/* succeeded */
1011
			$process_lock = true;
1012
			fclose($fd);
1013
			return;
1014
		} else {
1015
			/* file locked, wait and try again */
1016
			$process_lock = false;
1017
			sleep(1);
1018
			$n++;
1019
		}
1020
	}
1021
}
1022

    
1023
/* unlock configuration file */
1024
function config_unlock() {
1025
	global $g, $process_lock;
1026

    
1027
	$lockfile = "{$g['varrun_path']}/config.lock";
1028
	$process_lock = false;
1029

    
1030
	unlink_if_exists($lockfile);
1031
}
1032

    
1033
function set_networking_interfaces_ports() {
1034
	global $noreboot;
1035
	global $config;
1036
	global $g;
1037
	global $fp;
1038

    
1039
	$fp = fopen('php://stdin', 'r');
1040

    
1041
	$iflist = get_interface_list();
1042

    
1043
	echo <<<EOD
1044

    
1045
Valid interfaces are:
1046

    
1047

    
1048
EOD;
1049

    
1050
	if(!is_array($iflist)) {
1051
		echo "No interfaces found!\n";
1052
	} else {
1053
		foreach ($iflist as $iface => $ifa) {
1054
			echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1055
				$ifa['up'] ? "   (up)" : "");
1056
		}
1057
	}
1058

    
1059
	echo <<<EOD
1060

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

    
1065
Do you want to set up VLANs now [y|n]?
1066
EOD;
1067

    
1068
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
1069
		vlan_setup();
1070

    
1071
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1072

    
1073
		echo "\n\nVLAN interfaces:\n\n";
1074
		$i = 0;
1075
		foreach ($config['vlans']['vlan'] as $vlan) {
1076

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

    
1080
			$iflist['vlan' . $i] = array();
1081
			$i++;
1082
		}
1083
	}
1084

    
1085
	echo <<<EOD
1086

    
1087
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
1088
        If you do not have two interfaces turn off the machine until
1089
	you do.
1090

    
1091
If you do not know the names of your interfaces, you may choose to use
1092
auto-detection... In that case, disconnect all interfaces now before
1093
hitting a.   The system will then prompt you to plug in each nic to
1094
autodetect.
1095

    
1096
EOD;
1097

    
1098
	do {
1099
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
1100
		$lanif = chop(fgets($fp));
1101
		if ($lanif === "") {
1102
			return;
1103
		}
1104

    
1105
		if ($lanif === "a")
1106
			$lanif = autodetect_interface("LAN", $fp);
1107
		else if (!array_key_exists($lanif, $iflist)) {
1108
			echo "\nInvalid interface name '{$lanif}'\n";
1109
			unset($lanif);
1110
			continue;
1111
		}
1112
	} while (!$lanif);
1113

    
1114
	do {
1115
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
1116
		$wanif = chop(fgets($fp));
1117
		if ($wanif === "") {
1118
			return;
1119
		}
1120
		if ($wanif === "a")
1121
			$wanif = autodetect_interface("WAN", $fp);
1122
		else if (!array_key_exists($wanif, $iflist)) {
1123
			echo "\nInvalid interface name '{$wanif}'\n";
1124
			unset($wanif);
1125
			continue;
1126
		}
1127
	} while (!$wanif);
1128

    
1129
	/* optional interfaces */
1130
	$i = 0;
1131
	$optif = array();
1132

    
1133
	while (1) {
1134
		if ($optif[$i])
1135
			$i++;
1136
		$i1 = $i + 1;
1137

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

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

    
1144
		$optif[$i] = chop(fgets($fp));
1145

    
1146
		if ($optif[$i]) {
1147
			if ($optif[$i] === "a") {
1148
				$ad = autodetect_interface("Optional " . $i1, $fp);
1149
				if ($ad)
1150
					$optif[$i] = $ad;
1151
				else
1152
					unset($optif[$i]);
1153
			} else if (!array_key_exists($optif[$i], $iflist)) {
1154
				echo "\nInvalid interface name '{$optif[$i]}'\n";
1155
				unset($optif[$i]);
1156
				continue;
1157
			}
1158
		} else {
1159
			unset($optif[$i]);
1160
			break;
1161
		}
1162
	}
1163

    
1164
	/* check for double assignments */
1165
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1166

    
1167
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1168
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1169
			if ($ifarr[$i] == $ifarr[$j]) {
1170
				echo <<<EOD
1171

    
1172
Error: you cannot assign the same interface name twice!
1173

    
1174
EOD;
1175

    
1176
				return;
1177
			}
1178
		}
1179
	}
1180

    
1181
	echo <<<EOD
1182

    
1183
The interfaces will be assigned as follows:
1184

    
1185
LAN  -> {$lanif}
1186
WAN  -> {$wanif}
1187

    
1188
EOD;
1189

    
1190
	for ($i = 0; $i < count($optif); $i++) {
1191
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1192
	}
1193

    
1194
echo <<<EOD
1195

    
1196
Do you want to proceed [y|n]?
1197
EOD;
1198

    
1199
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1200

    
1201
		$config['interfaces']['lan']['if'] = $lanif;
1202
		if (preg_match($g['wireless_regex'], $lanif)) {
1203
			if (!is_array($config['interfaces']['lan']['wireless']))
1204
				$config['interfaces']['lan']['wireless'] = array();
1205
		} else {
1206
			unset($config['interfaces']['lan']['wireless']);
1207
		}
1208

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

    
1217
		for ($i = 0; $i < count($optif); $i++) {
1218
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1219
				$config['interfaces']['opt' . ($i+1)] = array();
1220

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

    
1223
			/* wireless interface? */
1224
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1225
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1226
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1227
			} else {
1228
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1229
			}
1230

    
1231
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1232
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1233
		}
1234

    
1235
		/* remove all other (old) optional interfaces */
1236
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1237
			unset($config['interfaces']['opt' . ($i+1)]);
1238

    
1239
		write_config();
1240

    
1241
		echo <<<EOD
1242

    
1243

    
1244

    
1245
EOD;
1246

    
1247
		if($g['booting'])
1248
			return;
1249

    
1250
		echo "One moment while we reload the settings...";
1251

    
1252
		$g['booting'] = false;
1253

    
1254
		/* resync everything */
1255
		reload_all_sync();
1256

    
1257
		echo " done!\n";
1258

    
1259
		touch("{$g['tmp_path']}/assign_complete");
1260

    
1261
	}
1262
}
1263

    
1264
function autodetect_interface($ifname, $fp) {
1265
	$iflist_prev = get_interface_list("media");
1266
	echo <<<EOD
1267

    
1268
Connect the {$ifname} interface now and make sure that the link is up.
1269
Then press ENTER to continue.
1270

    
1271
EOD;
1272
	fgets($fp);
1273
	$iflist = get_interface_list("media");
1274

    
1275
	foreach ($iflist_prev as $ifn => $ifa) {
1276
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1277
			echo "Detected link-up on interface {$ifn}.\n";
1278
			return $ifn;
1279
		}
1280
	}
1281

    
1282
	echo "No link-up detected.\n";
1283

    
1284
	return null;
1285
}
1286

    
1287
function vlan_setup() {
1288
	global $iflist, $config, $g, $fp;
1289

    
1290
	$iflist = get_interface_list();
1291

    
1292
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1293

    
1294
	echo <<<EOD
1295

    
1296
WARNING: all existing VLANs will be cleared if you proceed!
1297

    
1298
Do you want to proceed [y|n]?
1299
EOD;
1300

    
1301
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1302
		return;
1303
	}
1304

    
1305
	$config['vlans']['vlan'] = array();
1306
	echo "\n";
1307

    
1308
	while (1) {
1309
		$vlan = array();
1310

    
1311
		echo "\n\nVLAN Capable interfaces:\n\n";
1312
		if(!is_array($iflist)) {
1313
			echo "No interfaces found!\n";
1314
		} else {
1315
			$vlan_capable=0;
1316
			foreach ($iflist as $iface => $ifa) {
1317
				if (is_jumbo_capable($iface)) {
1318
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1319
						$ifa['up'] ? "   (up)" : "");
1320
					$vlan_capable++;
1321
				}
1322
			}
1323
		}
1324

    
1325
		if($vlan_capable == 0) {
1326
			echo "No VLAN capable interfaces detected.\n";
1327
			return;
1328
		}
1329

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

    
1333
		if ($vlan['if']) {
1334
			if (!array_key_exists($vlan['if'], $iflist) or
1335
			    !is_jumbo_capable($vlan['if'])) {
1336
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1337
				continue;
1338
			}
1339
		} else {
1340
			break;
1341
		}
1342

    
1343
		echo "Enter the VLAN tag (1-4094): ";
1344
		$vlan['tag'] = chop(fgets($fp));
1345

    
1346
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1347
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1348
			continue;
1349
		}
1350

    
1351
		$config['vlans']['vlan'][] = $vlan;
1352
	}
1353
}
1354

    
1355
function system_start_ftp_helpers() {
1356
	require_once("interfaces.inc");
1357
	global $config, $g;
1358

    
1359
	mwexec("/usr/bin/killall ftpsesame");
1360

    
1361
	/* build an array of interfaces to work with */
1362
	$iflist = array("lan" => "LAN");
1363
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
1364
		$iflist['opt' . $i] = "opt{$i}";
1365

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

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

    
1461
function get_backups() {
1462
	global $g;
1463
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1464
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1465
		$bakvers = array_keys($confvers);
1466
		$toreturn = array();
1467
		sort($bakvers);
1468
		// 	$bakvers = array_reverse($bakvers);
1469
		foreach(array_reverse($bakvers) as $bakver)
1470
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1471
	} else {
1472
		return false;
1473
	}
1474
	$toreturn['versions'] = $bakvers;
1475
	return $toreturn;
1476
}
1477

    
1478
function backup_config() {
1479
	global $config, $g;
1480

    
1481
	if($g['platform'] == "cdrom")
1482
		return;
1483

    
1484
	conf_mount_rw();
1485

    
1486
	/* Create backup directory if needed */
1487
	safe_mkdir("{$g['cf_conf_path']}/backup");
1488

    
1489
    if($config['revision']['time'] == "") {
1490
            $baktime = 0;
1491
    } else {
1492
            $baktime = $config['revision']['time'];
1493
    }
1494
    if($config['revision']['description'] == "") {
1495
            $bakdesc = "Unknown";
1496
    } else {
1497
            $bakdesc = $config['revision']['description'];
1498
    }
1499
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1500
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1501
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1502
    } else {
1503
            $backupcache = array();
1504
    }
1505
    $backupcache[$baktime] = array('description' => $bakdesc);
1506
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1507
    fwrite($bakout, serialize($backupcache));
1508
    fclose($bakout);
1509

    
1510
	conf_mount_ro();
1511

    
1512
	return true;
1513
}
1514

    
1515
function mute_kernel_msgs() {
1516
	exec("/sbin/conscontrol mute on");
1517
}
1518

    
1519
function unmute_kernel_msgs() {
1520
	exec("/sbin/conscontrol mute off");
1521
}
1522

    
1523
function start_devd() {
1524
	exec("/sbin/devd");
1525
	sleep(1);
1526
	if(file_exists("/tmp/rc.linkup"))
1527
		unlink("/tmp/rc.linkup");
1528
}
1529

    
1530
function set_device_perms() {
1531
	$devices = array(
1532
		'pf'	=> array(	'user'	=> 'proxy',
1533
					'group'	=> 'proxy',
1534
					'mode'	=> 0660),
1535
		);
1536

    
1537
	foreach ($devices as $name => $attr) {
1538
		$path = "/dev/$name";
1539
		if (file_exists($path)) {
1540
			chown($path, $attr['user']);
1541
			chgrp($path, $attr['group']);
1542
			chmod($path, $attr['mode']);
1543
		}
1544
	}
1545
}
1546

    
1547
if($g['booting']) echo ".";
1548

    
1549
?>
(5-5/27)