Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
173

    
174
EOD;
175

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

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

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

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

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

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

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

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

    
280
	return $config;
281
}
282

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

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

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

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

    
381
	parse_config(true);
382

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

    
386

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

    
395

    
396
EOD;
397
		}
398

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

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

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

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

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

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

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

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

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

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

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

    
486
	if ($config['version'] == $g['latest_config'])
487
		return;		/* already at latest version */
488

    
489
	// Save off config version
490
	$prev_version = $config['version'];
491

    
492
	/* convert 1.0 -> 1.1 */
493
	if ($config['version'] <= 1.0) {
494
		$opti = 1;
495
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
496

    
497
		/* convert DMZ to optional, if necessary */
498
		if (isset($config['interfaces']['dmz'])) {
499

    
500
			$dmzcfg = &$config['interfaces']['dmz'];
501

    
502
			if ($dmzcfg['if']) {
503
				$config['interfaces']['opt' . $opti] = array();
504
				$optcfg = &$config['interfaces']['opt' . $opti];
505

    
506
				$optcfg['enable'] = $dmzcfg['enable'];
507
				$optcfg['descr'] = "DMZ";
508
				$optcfg['if'] = $dmzcfg['if'];
509
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
510
				$optcfg['subnet'] = $dmzcfg['subnet'];
511

    
512
				$ifmap['dmz'] = "opt" . $opti;
513
				$opti++;
514
			}
515

    
516
			unset($config['interfaces']['dmz']);
517
		}
518

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

    
522
			if (!$config['interfaces']['wlan' . $i]['if']) {
523
				unset($config['interfaces']['wlan' . $i]);
524
				continue;
525
			}
526

    
527
			$wlancfg = &$config['interfaces']['wlan' . $i];
528
			$config['interfaces']['opt' . $opti] = array();
529
			$optcfg = &$config['interfaces']['opt' . $opti];
530

    
531
			$optcfg['enable'] = $wlancfg['enable'];
532
			$optcfg['descr'] = "WLAN" . $i;
533
			$optcfg['if'] = $wlancfg['if'];
534
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
535
			$optcfg['subnet'] = $wlancfg['subnet'];
536
			$optcfg['bridge'] = $wlancfg['bridge'];
537

    
538
			$optcfg['wireless'] = array();
539
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
540
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
541
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
542
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
543

    
544
			$ifmap['wlan' . $i] = "opt" . $opti;
545

    
546
			unset($config['interfaces']['wlan' . $i]);
547
			$opti++;
548
		}
549

    
550
		/* convert filter rules */
551
		$n = count($config['filter']['rule']);
552
		for ($i = 0; $i < $n; $i++) {
553

    
554
			$fr = &$config['filter']['rule'][$i];
555

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

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

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

    
594
		/* convert shaper rules */
595
		$n = count($config['pfqueueing']['rule']);
596
		if (is_array($config['pfqueueing']['rule']))
597
			for ($i = 0; $i < $n; $i++) {
598

    
599
			$fr = &$config['pfqueueing']['rule'][$i];
600

    
601
			/* remap interface */
602
			if (array_key_exists($fr['interface'], $ifmap))
603
				$fr['interface'] = $ifmap[$fr['interface']];
604
			else {
605
				/* remove the rule */
606
				echo "\nWarning: traffic shaper rule removed " .
607
					"(interface '{$fr['interface']}' does not exist anymore).";
608
				unset($config['pfqueueing']['rule'][$i]);
609
				continue;
610
			}
611

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

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

    
639
		$config['version'] = "1.1";
640
	}
641

    
642
	/* convert 1.1 -> 1.2 */
643
	if ($config['version'] <= 1.1) {
644
		/* move LAN DHCP server config */
645
		$tmp = $config['dhcpd'];
646
		$config['dhcpd'] = array();
647
		$config['dhcpd']['lan'] = $tmp;
648

    
649
		/* encrypt password */
650
		$config['system']['password'] = crypt($config['system']['password']);
651

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

    
655
	/* convert 1.2 -> 1.3 */
656
	if ($config['version'] <= 1.2) {
657
		/* convert advanced outbound NAT config */
658
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
659
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
660
			$src = $curent['source'];
661
			$curent['source'] = array();
662
			$curent['source']['network'] = $src;
663
			$curent['destination'] = array();
664
			$curent['destination']['any'] = true;
665
		}
666

    
667
		/* add an explicit type="pass" to all filter rules to make things consistent */
668
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
669
			$config['filter']['rule'][$i]['type'] = "pass";
670
		}
671

    
672
		$config['version'] = "1.3";
673
	}
674

    
675
	/* convert 1.3 -> 1.4 */
676
	if ($config['version'] <= 1.3) {
677
		/* convert shaper rules (make pipes) */
678
		if (is_array($config['pfqueueing']['rule'])) {
679
			$config['pfqueueing']['pipe'] = array();
680

    
681
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
682
				$curent = &$config['pfqueueing']['rule'][$i];
683

    
684
				/* make new pipe and associate with this rule */
685
				$newpipe = array();
686
				$newpipe['descr'] = $curent['descr'];
687
				$newpipe['bandwidth'] = $curent['bandwidth'];
688
				$newpipe['delay'] = $curent['delay'];
689
				$newpipe['mask'] = $curent['mask'];
690
				$config['pfqueueing']['pipe'][$i] = $newpipe;
691

    
692
				$curent['targetpipe'] = $i;
693

    
694
				unset($curent['bandwidth']);
695
				unset($curent['delay']);
696
				unset($curent['mask']);
697
			}
698
		}
699

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

    
703
	/* Convert 1.4 -> 1.5 */
704
	if ($config['version'] <= 1.4) {
705

    
706
		/* Default route moved */
707
		if (isset($config['interfaces']['wan']['gateway']))
708
			if ($config['interfaces']['wan']['gateway'] <> "")
709
				$config['interfaces']['wan']['gateway'] = $config['interfaces']['wan']['gateway'];
710
		unset($config['interfaces']['wan']['gateway']);
711

    
712
                /* Queues are no longer interface specific */
713
                if (isset($config['interfaces']['lan']['schedulertype']))
714
                        unset($config['interfaces']['lan']['schedulertype']);
715
                if (isset($config['interfaces']['wan']['schedulertype']))
716
                        unset($config['interfaces']['wan']['schedulertype']);
717

    
718
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
719
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
720
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
721
                }
722

    
723
		$config['version'] = "1.5";
724
	}
725

    
726
	/* Convert 1.5 -> 1.6 */
727
	if ($config['version'] <= 1.5) {
728
		/* Alternate firmware URL moved */
729
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
730
			$config['system']['alt_firmware_url'] = array();
731
			$config['system']['alt_firmware_url']['enabled'] = "";
732
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
733
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
734
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
735
		} else {
736
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
737
		}
738

    
739
		$config['version'] = "1.6";
740
	}
741

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

    
801
		/* enable SSH */
802
		if ($config['version'] == "1.8") {
803
			$config['system']['sshenabled'] = true;
804
		}
805

    
806
		$config['version'] = "1.9";
807
	}
808

    
809
	/* Convert 1.8 -> 1.9 */
810
	if ($config['version'] <= 1.8) {
811
		$config['theme']="metallic";
812
		$config['version'] = "1.9";
813
	}
814
	/* Convert 1.9 -> 2.0 */
815
	if ($config['version'] <= 1.9) {
816
		if(is_array($config['ipsec']['tunnel'])) {
817
			reset($config['ipsec']['tunnel']);
818
			while (list($index, $tunnel) = each($config['ipsec']['tunnel'])) {
819
				/* Sanity check on required variables */
820
				/* This fixes bogus <tunnel> entries - remnant of bug #393 */
821
				if (!isset($tunnel['local-subnet']) && !isset($tunnel['remote-subnet'])) {
822
					unset($config['ipsec']['tunnel'][$tunnel]);
823
				}
824
			}
825
        	}
826
		$config['version'] = "2.0";
827
	}
828
	/* Convert 2.0 -> 2.1 */
829
	if ($config['version'] <= 2.0) {
830
		/* shaper scheduler moved */
831
		if(isset($config['system']['schedulertype'])) {
832
			$config['shaper']['schedulertype'] = $config['system']['schedulertype'];
833
			unset($config['system']['schedulertype']);
834
		}
835
		$config['version'] = "2.1";
836
	}
837
	/* Convert 2.1 -> 2.2 */
838
	if ($config['version'] <= 2.1) {
839
		/* move gateway to wan interface */
840
		$config['interfaces']['wan']['gateway'] = $config['system']['gateway'];
841
		$config['version'] = "2.2";
842
	}
843
	/* Convert 2.2 -> 2.3 */
844
	if ($config['version'] <= 2.2) {
845
		if(isset($config['shaper'])) {
846
			/* wipe previous shaper configuration */
847
			unset($config['shaper']);
848
		}
849
		$config['version'] = "2.3";
850
	}
851

    
852
	/* Convert 2.4 -> 2.5 */
853
	if ($config['version'] <= 2.4) {
854
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
855
		unset($config['system']['use_rrd_gateway']);
856
 		$config['version'] = "2.5";
857
	}
858

    
859
	/* Convert 2.5 -> 2.6 */
860
	if ($config['version'] <= 2.5) {
861
		$cron_item = array();
862
		$cron_item['minute'] = "0";
863
		$cron_item['hour'] = "*";
864
		$cron_item['mday'] = "*";
865
		$cron_item['month'] = "*";
866
		$cron_item['wday'] = "*";
867
		$cron_item['who'] = "root";
868
		$cron_item['command'] = "/usr/bin/nice -n20 newsyslog";
869

    
870
		$config['cron']['item'][] = $cron_item;
871

    
872
		$cron_item = array();
873
		$cron_item['minute'] = "1,31";
874
		$cron_item['hour'] = "0-5";
875
		$cron_item['mday'] = "*";
876
		$cron_item['month'] = "*";
877
		$cron_item['wday'] = "*";
878
		$cron_item['who'] = "root";
879
		$cron_item['command'] = "/usr/bin/nice -n20 adjkerntz -a";
880

    
881
		$config['cron']['item'][] = $cron_item;
882

    
883
		$cron_item = array();
884
		$cron_item['minute'] = "1";
885
		$cron_item['hour'] = "*";
886
		$cron_item['mday'] = "1";
887
		$cron_item['month'] = "*";
888
		$cron_item['wday'] = "*";
889
		$cron_item['who'] = "root";
890
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.update_bogons.sh";
891

    
892
		$config['cron']['item'][] = $cron_item;
893

    
894
		$cron_item = array();
895
		$cron_item['minute'] = "*/60";
896
		$cron_item['hour'] = "*";
897
		$cron_item['mday'] = "*";
898
		$cron_item['month'] = "*";
899
		$cron_item['wday'] = "*";
900
		$cron_item['who'] = "root";
901
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 sshlockout";
902

    
903
		$config['cron']['item'][] = $cron_item;
904

    
905
		$cron_item = array();
906
		$cron_item['minute'] = "1";
907
		$cron_item['hour'] = "1";
908
		$cron_item['mday'] = "*";
909
		$cron_item['month'] = "*";
910
		$cron_item['wday'] = "*";
911
		$cron_item['who'] = "root";
912
		$cron_item['command'] = "/usr/bin/nice -n20 /etc/rc.dyndns.update";
913

    
914
		$config['cron']['item'][] = $cron_item;
915

    
916
		$cron_item = array();
917
		$cron_item['minute'] = "*/60";
918
		$cron_item['hour'] = "*";
919
		$cron_item['mday'] = "*";
920
		$cron_item['month'] = "*";
921
		$cron_item['wday'] = "*";
922
		$cron_item['who'] = "root";
923
		$cron_item['command'] = "/usr/bin/nice -n20 /usr/local/sbin/expiretable -v -t 3600 virusprot";
924

    
925
		$config['cron']['item'][] = $cron_item;
926

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

    
936
		$config['cron']['item'][] = $cron_item;
937

    
938
		$cron_item = array();
939
		$cron_item['minute'] = "*/5";
940
		$cron_item['hour'] = "*";
941
		$cron_item['mday'] = "*";
942
		$cron_item['month'] = "*";
943
		$cron_item['wday'] = "*";
944
		$cron_item['who'] = "root";
945
		$cron_item['command'] = "/usr/local/bin/checkreload.sh";
946

    
947
		$config['cron']['item'][] = $cron_item;
948

    
949
		/* write crontab entries to file */
950
		configure_cron();
951

    
952
 		$config['version'] = "2.6";
953
	}
954

    
955
	/* Convert 2.6 -> 2.7 */
956
	if ($config['version'] <= 2.6) {
957
		$config['interfaces']['wan']['use_rrd_gateway'] = $config['system']['use_rrd_gateway'];
958
		unset($config['system']['use_rrd_gateway']);
959
		$config['version'] = "2.7";
960
	}
961

    
962
	/* Convert 2.7 -> 2.8 */
963
	if ($config['version'] <= 2.7) {
964
		$founditem = false;
965
		foreach($config['cron']['item'] as $cronitem) {
966
			if($cronitem['command'] == "/usr/local/bin/checkreload.sh")
967
				$founditem = true;
968
		}
969
		if($founditem == false) {
970
			$cron_item = array();
971
			$cron_item['minute'] = "*/5";
972
			$cron_item['hour'] = "*";
973
			$cron_item['mday'] = "*";
974
			$cron_item['month'] = "*";
975
			$cron_item['wday'] = "*";
976
			$cron_item['who'] = "root";
977
			$cron_item['command'] = "/usr/local/bin/checkreload.sh";
978
			$config['cron']['item'][] = $cron_item;
979
		}
980
		$config['version'] = "2.8";
981
	}
982

    
983
	/* Convert 2.8 -> 2.9 */
984
	if ($config['version'] <= 2.8) {
985
		$rule_item = array();
986
		$a_filter = &$config['filter']['rule'];
987
		$rule_item['interface'] = "enc0";
988
		$rule_item['type'] = "pass";
989
		$rule_item['source']['any'] = true;
990
		$rule_item['destination']['any'] = true;
991
		$rule_item['descr'] = "Permit IPSEC traffic.";
992
		$rule_item['statetype'] = "keep state";
993
		$a_filter[] = $rule_item;
994
		$config['version'] = "2.9";
995
	}
996

    
997
	if ($prev_version != $config['version'])
998
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
999
}
1000

    
1001
/****f* config/write_config
1002
 * NAME
1003
 *   write_config - Backup and write the firewall configuration.
1004
 * DESCRIPTION
1005
 *   write_config() handles backing up the current configuration,
1006
 *   applying changes, and regenerating the configuration cache.
1007
 * INPUTS
1008
 *   $desc	- string containing the a description of configuration changes
1009
 *   $backup	- boolean: do not back up current configuration if false.
1010
 * RESULT
1011
 *   null
1012
 ******/
1013
/* save the system configuration */
1014
function write_config($desc="Unknown", $backup = true) {
1015
	global $config, $g;
1016

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

    
1020
	if($backup)
1021
		backup_config();
1022

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

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

    
1030
	$config['revision']['description'] = $desc;
1031
	$config['revision']['time'] = $changetime;
1032

    
1033
	config_lock();
1034

    
1035
	/* generate configuration XML */
1036
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
1037

    
1038
	conf_mount_rw();
1039

    
1040
	/* write new configuration */
1041
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
1042
	if (!$fd)
1043
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
1044
	fwrite($fd, $xmlconfig);
1045
	fclose($fd);
1046

    
1047
	if($g['platform'] == "embedded") {
1048
		cleanup_backupcache(5);
1049
	} else {
1050
		cleanup_backupcache(30);
1051
	}
1052

    
1053
	if($g['booting'] <> true) {
1054
		conf_mount_ro();
1055
	}
1056

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

    
1060
	/* write config cache */
1061
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
1062
	if ($fd) {
1063
		fwrite($fd, serialize($config));
1064
		fclose($fd);
1065
	}
1066

    
1067
	/* tell kernel to sync fs data */
1068
	mwexec("/bin/sync");
1069

    
1070
	config_unlock();
1071

    
1072
	return $config;
1073
}
1074

    
1075
/****f* config/reset_factory_defaults
1076
 * NAME
1077
 *   reset_factory_defaults - Reset the system to its default configuration.
1078
 * RESULT
1079
 *   integer	- indicates completion
1080
 ******/
1081
function reset_factory_defaults() {
1082
	global $g;
1083

    
1084
	config_lock();
1085
	conf_mount_rw();
1086

    
1087
	/* create conf directory, if necessary */
1088
	safe_mkdir("{$g['cf_conf_path']}");
1089

    
1090
	/* clear out /conf */
1091
	$dh = opendir($g['conf_path']);
1092
	while ($filename = readdir($dh)) {
1093
		if (($filename != ".") && ($filename != "..")) {
1094
			unlink_if_exists($g['conf_path'] . "/" . $filename);
1095
		}
1096
	}
1097
	closedir($dh);
1098

    
1099
	/* copy default configuration */
1100
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
1101

    
1102
	/* call the wizard */
1103
	touch("/conf/trigger_initial_wizard");
1104

    
1105
	conf_mount_ro();
1106
	config_unlock();
1107

    
1108
	return 0;
1109
}
1110

    
1111
function config_restore($conffile) {
1112
	global $config, $g;
1113

    
1114
	if (!file_exists($conffile))
1115
		return 1;
1116

    
1117
    config_lock();
1118
    conf_mount_rw();
1119

    
1120
    backup_config();
1121
    copy($conffile, "{$g['cf_conf_path']}/config.xml");
1122
	$config = parse_config(true);
1123
    write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
1124

    
1125
    conf_mount_ro();
1126
    config_unlock();
1127

    
1128
    return 0;
1129
}
1130

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

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

    
1137
	if (!config_validate("{$g['conf_path']}/config.xml"))
1138
		return 1;
1139

    
1140
	if($g['booting'] == true)
1141
		echo "Installing configuration...\n";
1142

    
1143
    config_lock();
1144
    conf_mount_rw();
1145

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

    
1148
	/* unlink cache file if it exists */
1149
	if(file_exists("{$g['tmp_path']}/config.cache"))
1150
		unlink("{$g['tmp_path']}/config.cache");
1151

    
1152
    conf_mount_ro();
1153
    config_unlock();
1154

    
1155
    return 0;
1156
}
1157

    
1158
function config_validate($conffile) {
1159

    
1160
	global $g, $xmlerr;
1161

    
1162
	$xml_parser = xml_parser_create();
1163

    
1164
	if (!($fp = fopen($conffile, "r"))) {
1165
		$xmlerr = "XML error: unable to open file";
1166
		return false;
1167
	}
1168

    
1169
	while ($data = fread($fp, 4096)) {
1170
		if (!xml_parse($xml_parser, $data, feof($fp))) {
1171
			$xmlerr = sprintf("%s at line %d",
1172
						xml_error_string(xml_get_error_code($xml_parser)),
1173
						xml_get_current_line_number($xml_parser));
1174
			return false;
1175
		}
1176
	}
1177
	xml_parser_free($xml_parser);
1178

    
1179
	fclose($fp);
1180

    
1181
	return true;
1182
}
1183

    
1184
/*   lock configuration file, decide that the lock file
1185
 *   is stale after 10 seconds
1186
 */
1187
function config_lock() {
1188
	global $g, $process_lock;
1189

    
1190
	/* No need to continue if we're the ones holding the lock */
1191
	if ($process_lock)
1192
		return;
1193

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

    
1196
	$n = 0;
1197
	while ($n < 10) {
1198
		/* open the lock file in append mode to avoid race condition */
1199
		if ($fd = @fopen($lockfile, "x")) {
1200
			/* succeeded */
1201
			$process_lock = true;
1202
			fclose($fd);
1203
			return;
1204
		} else {
1205
			/* file locked, wait and try again */
1206
			if($n == 4) 
1207
				log_error("[DEBUG] Lock recursion detected.");
1208
			$process_lock = false;
1209
			sleep(1);
1210
			$n++;
1211
		}
1212
	}
1213
}
1214

    
1215
/* unlock configuration file */
1216
function config_unlock() {
1217
	global $g, $process_lock;
1218

    
1219
	$lockfile = "{$g['varrun_path']}/config.lock";
1220
	$process_lock = false;
1221

    
1222
	unlink_if_exists($lockfile);
1223
}
1224

    
1225
function set_networking_interfaces_ports() {
1226
	global $noreboot;
1227
	global $config;
1228
	global $g;
1229
	global $fp;
1230

    
1231
	$fp = fopen('php://stdin', 'r');
1232

    
1233
	$memory = get_memory();
1234
	$avail = $memory[0];
1235

    
1236
	if($avail < 115) {
1237
		echo "\n\n\n";
1238
		echo "DANGER!  WARNING!\n\n";
1239
		echo "pfSense requires *ATLEAST* 128 megs of ram to function correctly.\n";
1240
		echo "Only ($avail) megs of ram has been detected.\n";
1241
		echo "\nPress ENTER to continue.";
1242
		fgets($fp);
1243
		echo "\n";
1244
	}
1245

    
1246
	$iflist = get_interface_list();
1247

    
1248
	echo <<<EOD
1249

    
1250
Valid interfaces are:
1251

    
1252

    
1253
EOD;
1254

    
1255
	if(!is_array($iflist)) {
1256
		echo "No interfaces found!\n";
1257
	} else {
1258
		foreach ($iflist as $iface => $ifa) {
1259
			echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1260
				$ifa['up'] ? "   (up)" : "");
1261
		}
1262
	}
1263

    
1264
	echo <<<EOD
1265

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

    
1270
Do you want to set up VLANs now [y|n]?
1271
EOD;
1272

    
1273
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
1274
		vlan_setup();
1275

    
1276
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1277

    
1278
		echo "\n\nVLAN interfaces:\n\n";
1279
		$i = 0;
1280
		foreach ($config['vlans']['vlan'] as $vlan) {
1281

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

    
1285
			$iflist['vlan' . $i] = array();
1286
			$i++;
1287
		}
1288
	}
1289

    
1290
	echo <<<EOD
1291

    
1292
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
1293
        If you do not have two interfaces turn off the machine until
1294
	    you do.
1295

    
1296
	    And now in ENGLISH.  If you do not have atleast two *REAL*
1297
	    network interface cards or one nic with multiple VLANS then
1298
	    pfSense *WILL NOT* run correctly.
1299

    
1300
If you do not know the names of your interfaces, you may choose to use
1301
auto-detection... In that case, disconnect all interfaces now before
1302
hitting a.   The system will then prompt you to plug in each nic to
1303
autodetect.
1304

    
1305
EOD;
1306

    
1307
	do {
1308
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
1309
		$lanif = chop(fgets($fp));
1310
		if ($lanif === "") {
1311
			return;
1312
		}
1313

    
1314
		if ($lanif === "a")
1315
			$lanif = autodetect_interface("LAN", $fp);
1316
		else if (!array_key_exists($lanif, $iflist)) {
1317
			echo "\nInvalid interface name '{$lanif}'\n";
1318
			unset($lanif);
1319
			continue;
1320
		}
1321
	} while (!$lanif);
1322

    
1323
	do {
1324
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
1325
		$wanif = chop(fgets($fp));
1326
		if ($wanif === "") {
1327
			return;
1328
		}
1329
		if ($wanif === "a")
1330
			$wanif = autodetect_interface("WAN", $fp);
1331
		else if (!array_key_exists($wanif, $iflist)) {
1332
			echo "\nInvalid interface name '{$wanif}'\n";
1333
			unset($wanif);
1334
			continue;
1335
		}
1336
	} while (!$wanif);
1337

    
1338
	/* optional interfaces */
1339
	$i = 0;
1340
	$optif = array();
1341

    
1342
	while (1) {
1343
		if ($optif[$i])
1344
			$i++;
1345
		$i1 = $i + 1;
1346

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

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

    
1353
		$optif[$i] = chop(fgets($fp));
1354

    
1355
		if ($optif[$i]) {
1356
			if ($optif[$i] === "a") {
1357
				$ad = autodetect_interface("Optional " . $i1, $fp);
1358
				if ($ad)
1359
					$optif[$i] = $ad;
1360
				else
1361
					unset($optif[$i]);
1362
			} else if (!array_key_exists($optif[$i], $iflist)) {
1363
				echo "\nInvalid interface name '{$optif[$i]}'\n";
1364
				unset($optif[$i]);
1365
				continue;
1366
			}
1367
		} else {
1368
			unset($optif[$i]);
1369
			break;
1370
		}
1371
	}
1372

    
1373
	/* check for double assignments */
1374
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1375

    
1376
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1377
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1378
			if ($ifarr[$i] == $ifarr[$j]) {
1379
				echo <<<EOD
1380

    
1381
Error: you cannot assign the same interface name twice!
1382

    
1383
EOD;
1384

    
1385
				return;
1386
			}
1387
		}
1388
	}
1389

    
1390
	echo <<<EOD
1391

    
1392
The interfaces will be assigned as follows:
1393

    
1394
LAN  -> {$lanif}
1395
WAN  -> {$wanif}
1396

    
1397
EOD;
1398

    
1399
	for ($i = 0; $i < count($optif); $i++) {
1400
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1401
	}
1402

    
1403
echo <<<EOD
1404

    
1405
Do you want to proceed [y|n]?
1406
EOD;
1407

    
1408
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1409

    
1410
		$config['interfaces']['lan']['if'] = $lanif;
1411
		if (preg_match($g['wireless_regex'], $lanif)) {
1412
			if (!is_array($config['interfaces']['lan']['wireless']))
1413
				$config['interfaces']['lan']['wireless'] = array();
1414
		} else {
1415
			unset($config['interfaces']['lan']['wireless']);
1416
		}
1417

    
1418
		$config['interfaces']['wan']['if'] = $wanif;
1419
		if (preg_match($g['wireless_regex'], $wanif)) {
1420
			if (!is_array($config['interfaces']['wan']['wireless']))
1421
				$config['interfaces']['wan']['wireless'] = array();
1422
		} else {
1423
			unset($config['interfaces']['wan']['wireless']);
1424
		}
1425

    
1426
		for ($i = 0; $i < count($optif); $i++) {
1427
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1428
				$config['interfaces']['opt' . ($i+1)] = array();
1429

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

    
1432
			/* wireless interface? */
1433
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1434
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1435
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1436
			} else {
1437
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1438
			}
1439

    
1440
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1441
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1442
		}
1443

    
1444
		/* remove all other (old) optional interfaces */
1445
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1446
			unset($config['interfaces']['opt' . ($i+1)]);
1447

    
1448
		write_config();
1449

    
1450
		echo <<<EOD
1451

    
1452

    
1453

    
1454
EOD;
1455

    
1456
		if($g['booting'])
1457
			return;
1458

    
1459
		echo "One moment while we reload the settings...";
1460

    
1461
		$g['booting'] = false;
1462

    
1463
		/* resync everything */
1464
		reload_all_sync();
1465

    
1466
		echo " done!\n";
1467

    
1468
		touch("{$g['tmp_path']}/assign_complete");
1469

    
1470
	}
1471
}
1472

    
1473
function autodetect_interface($ifname, $fp) {
1474
	$iflist_prev = get_interface_list("media");
1475
	echo <<<EOD
1476

    
1477
Connect the {$ifname} interface now and make sure that the link is up.
1478
Then press ENTER to continue.
1479

    
1480
EOD;
1481
	fgets($fp);
1482
	$iflist = get_interface_list("media");
1483

    
1484
	foreach ($iflist_prev as $ifn => $ifa) {
1485
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1486
			echo "Detected link-up on interface {$ifn}.\n";
1487
			return $ifn;
1488
		}
1489
	}
1490

    
1491
	echo "No link-up detected.\n";
1492

    
1493
	return null;
1494
}
1495

    
1496
function vlan_setup() {
1497
	global $iflist, $config, $g, $fp;
1498

    
1499
	$iflist = get_interface_list();
1500

    
1501
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1502

    
1503
	echo <<<EOD
1504

    
1505
WARNING: all existing VLANs will be cleared if you proceed!
1506

    
1507
Do you want to proceed [y|n]?
1508
EOD;
1509

    
1510
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1511
		return;
1512
	}
1513

    
1514
	$config['vlans']['vlan'] = array();
1515
	echo "\n";
1516

    
1517
	while (1) {
1518
		$vlan = array();
1519

    
1520
		echo "\n\nVLAN Capable interfaces:\n\n";
1521
		if(!is_array($iflist)) {
1522
			echo "No interfaces found!\n";
1523
		} else {
1524
			$vlan_capable=0;
1525
			foreach ($iflist as $iface => $ifa) {
1526
				if (is_jumbo_capable($iface)) {
1527
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1528
						$ifa['up'] ? "   (up)" : "");
1529
					$vlan_capable++;
1530
				}
1531
			}
1532
		}
1533

    
1534
		if($vlan_capable == 0) {
1535
			echo "No VLAN capable interfaces detected.\n";
1536
			return;
1537
		}
1538

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

    
1542
		if ($vlan['if']) {
1543
			if (!array_key_exists($vlan['if'], $iflist) or
1544
			    !is_jumbo_capable($vlan['if'])) {
1545
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1546
				continue;
1547
			}
1548
		} else {
1549
			break;
1550
		}
1551

    
1552
		echo "Enter the VLAN tag (1-4094): ";
1553
		$vlan['tag'] = chop(fgets($fp));
1554

    
1555
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1556
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1557
			continue;
1558
		}
1559

    
1560
		$config['vlans']['vlan'][] = $vlan;
1561
	}
1562
}
1563

    
1564
function system_start_ftp_helpers() {
1565
	require_once("interfaces.inc");
1566
	global $config, $g;
1567

    
1568
	mwexec("/usr/bin/killall ftpsesame");
1569

    
1570
	/* build an array of interfaces to work with */
1571
	$iflist = array("lan" => "LAN");
1572
	for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++)
1573
		$iflist['opt' . $i] = "opt{$i}";
1574

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

    
1653
function cleanup_backupcache($revisions = 30) {
1654
	global $g;
1655
	$i = false;
1656
	config_lock();
1657
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1658
		conf_mount_rw();
1659
		$backups = get_backups();
1660
		$newbaks = array();
1661
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1662
		$baktimes = $backups['versions'];
1663
		$tocache = array();
1664
		unset($backups['versions']);
1665
   		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1666
   			if(filesize($backup) == 0) {
1667
   				unlink($backup);
1668
   				continue;
1669
   			}
1670
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1671
            if(!in_array($tocheck, $baktimes)) {
1672
				$i = true;
1673
				if($g['booting'])
1674
					print " " . $tocheck . "a";
1675
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1676
				if($newxml == "-1") {
1677
					unlink($backup);
1678
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1679
					continue;
1680
				}
1681
				if($newxml['revision']['description'] == "")
1682
					$newxml['revision']['description'] = "Unknown";
1683
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1684
			}
1685
    	}
1686
		foreach($backups as $checkbak) {
1687

    
1688
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1689
				$newbaks[] = $checkbak;
1690
			} else {
1691
				$i = true;
1692
				if($g['booting']) print " " . $tocheck . "r";
1693
			}
1694
		}
1695
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1696
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1697
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1698
			foreach($toslice as $sliced)
1699
				$newcache[$sliced] = $tocache[$sliced];
1700
			foreach($tocache as $version => $versioninfo) {
1701
				if(!in_array($version, array_keys($newcache))) {
1702
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1703
					if($g['booting']) print " " . $tocheck . "d";
1704
				}
1705
			}
1706
			$tocache = $newcache;
1707
		}
1708
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1709
        fwrite($bakout, serialize($tocache));
1710
		fclose($bakout);
1711
		conf_mount_ro();
1712
	}
1713
	if($g['booting']) {
1714
		if($i) {
1715
			print "done.\n";
1716
		}
1717
	}
1718
	config_unlock();
1719
}
1720

    
1721
function get_backups() {
1722
	global $g;
1723
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1724
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1725
		$bakvers = array_keys($confvers);
1726
		$toreturn = array();
1727
		sort($bakvers);
1728
		// 	$bakvers = array_reverse($bakvers);
1729
		foreach(array_reverse($bakvers) as $bakver)
1730
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1731
	} else {
1732
		return false;
1733
	}
1734
	$toreturn['versions'] = $bakvers;
1735
	return $toreturn;
1736
}
1737

    
1738
function backup_config() {
1739
	global $config, $g;
1740

    
1741
	if($g['platform'] == "cdrom")
1742
		return;
1743

    
1744
	conf_mount_rw();
1745

    
1746
	/* Create backup directory if needed */
1747
	safe_mkdir("{$g['cf_conf_path']}/backup");
1748

    
1749
    if($config['revision']['time'] == "") {
1750
            $baktime = 0;
1751
    } else {
1752
            $baktime = $config['revision']['time'];
1753
    }
1754
    if($config['revision']['description'] == "") {
1755
            $bakdesc = "Unknown";
1756
    } else {
1757
            $bakdesc = $config['revision']['description'];
1758
    }
1759
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1760
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1761
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1762
    } else {
1763
            $backupcache = array();
1764
    }
1765
    $backupcache[$baktime] = array('description' => $bakdesc);
1766
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1767
    fwrite($bakout, serialize($backupcache));
1768
    fclose($bakout);
1769

    
1770
	conf_mount_ro();
1771

    
1772
	return true;
1773
}
1774

    
1775
function mute_kernel_msgs() {
1776
	exec("/sbin/conscontrol mute on");
1777
}
1778

    
1779
function unmute_kernel_msgs() {
1780
	exec("/sbin/conscontrol mute off");
1781
}
1782

    
1783
function start_devd() {
1784
	exec("/sbin/devd");
1785
	sleep(1);
1786
	if(file_exists("/tmp/rc.linkup"))
1787
		unlink("/tmp/rc.linkup");
1788
}
1789

    
1790
function is_interface_mismatch() {
1791
	global $config, $g;
1792
	$lan_if = $config['interfaces']['lan']['if'];
1793
	$wan_if = get_real_wan_interface();
1794
	$do_assign = 0;
1795
	/* we need to ignore the vlan interface checks) */
1796
	if (stristr($lan_if, "vlan") == false and stristr($wan_if, "vlan") == false) {
1797
		if (does_interface_exist($lan_if) == false)
1798
			$do_assign = 1;
1799
		if ($config['interfaces']['wan']['ipaddr'] <> "pppoe" && $config['interfaces']['wan']['ipaddr'] <> "pptp" && $do_assign == 0)
1800
			if (does_interface_exist($wan_if) == false)
1801
				$do_assign = 1;
1802
	}
1803
	/* XXX: enumerate OPT interfaces looking for mismatches */
1804
	if (file_exists("{$g['tmp_path']}/assign_complete"))
1805
		return false;
1806
	if ($do_assign == 1)
1807
		return true;
1808
	else
1809
		return false;
1810
}
1811

    
1812
function set_device_perms() {
1813
	$devices = array(
1814
		'pf'	=> array(	'user'	=> 'proxy',
1815
					'group'	=> 'proxy',
1816
					'mode'	=> 0660),
1817
		);
1818

    
1819
	foreach ($devices as $name => $attr) {
1820
		$path = "/dev/$name";
1821
		if (file_exists($path)) {
1822
			chown($path, $attr['user']);
1823
			chgrp($path, $attr['group']);
1824
			chmod($path, $attr['mode']);
1825
		}
1826
	}
1827
}
1828

    
1829
if($g['booting']) echo ".";
1830
$config = parse_config();
1831

    
1832
?>
(5-5/27)