Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
173

    
174
EOD;
175

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

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

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

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

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

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

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

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

    
280
	return $config;
281
}
282

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

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

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

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

    
381
	parse_config(true);
382

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

    
386

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

    
395

    
396
EOD;
397
		}
398

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

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

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

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

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

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

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

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

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

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

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

    
486
	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
	/* Convert 2.9 -> 3.0 */
998
	if ($config['version'] <= 2.9) {
999
		/* enable the rrd config setting by default */
1000
		$config['rrd']['enable'] = true;
1001
		$config['version'] = "3.0";
1002
 	}
1003

    
1004
	/* special case upgrades */
1005
	/* fix every minute crontab bogons entry */
1006
	$cron_item_count = count($config['cron']['item']);
1007
	for($x=0; $x<$cron_item_count; $x++) {
1008
	        if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
1009
	        	if($config['cron']['item'][$x]['hour'] == "*" ) {
1010
	                $config['cron']['item'][$x]['hour'] = "2";
1011
	         		write_config("Updated bogon update frequency to 2am");
1012
	         	}       
1013
			}
1014
	}
1015

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

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

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

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

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

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

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

    
1052
	config_lock();
1053

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

    
1057
	conf_mount_rw();
1058

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

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

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

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

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

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

    
1089
	config_unlock();
1090

    
1091
	return $config;
1092
}
1093

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

    
1103
	config_lock();
1104
	conf_mount_rw();
1105

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

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

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

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

    
1124
	conf_mount_ro();
1125
	config_unlock();
1126

    
1127
	return 0;
1128
}
1129

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

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

    
1136
    config_lock();
1137
    conf_mount_rw();
1138

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

    
1144
    conf_mount_ro();
1145
    config_unlock();
1146

    
1147
    return 0;
1148
}
1149

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

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

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

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

    
1162
    config_lock();
1163
    conf_mount_rw();
1164

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

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

    
1171
    conf_mount_ro();
1172
    config_unlock();
1173

    
1174
    return 0;
1175
}
1176

    
1177
function config_validate($conffile) {
1178

    
1179
	global $g, $xmlerr;
1180

    
1181
	$xml_parser = xml_parser_create();
1182

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

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

    
1198
	fclose($fp);
1199

    
1200
	return true;
1201
}
1202

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

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

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

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

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

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

    
1241
	unlink_if_exists($lockfile);
1242
}
1243

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

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

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

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

    
1265
	$iflist = get_interface_list();
1266

    
1267
	echo <<<EOD
1268

    
1269
Valid interfaces are:
1270

    
1271

    
1272
EOD;
1273

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

    
1283
	echo <<<EOD
1284

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

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

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

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

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

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

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

    
1309
	echo <<<EOD
1310

    
1311
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
1312
        If you do not have two interfaces turn off the machine until
1313
	    you do.
1314

    
1315
	    And now in ENGLISH.  If you do not have atleast two *REAL*
1316
	    network interface cards or one nic with multiple VLANS then
1317
	    pfSense *WILL NOT* run correctly.
1318

    
1319
If you do not know the names of your interfaces, you may choose to use
1320
auto-detection... In that case, disconnect all interfaces now before
1321
hitting a.   The system will then prompt you to plug in each nic to
1322
autodetect.
1323

    
1324
EOD;
1325

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1414
	echo <<<EOD
1415

    
1416
The interfaces will be assigned as follows:
1417

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

    
1421
EOD;
1422

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

    
1427
echo <<<EOD
1428

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

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

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

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

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

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

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

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

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

    
1472
		write_config();
1473

    
1474
		echo <<<EOD
1475

    
1476

    
1477

    
1478
EOD;
1479

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

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

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

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

    
1492
		echo " done!\n";
1493

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

    
1496
	}
1497
}
1498

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

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

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

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

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

    
1519
	return null;
1520
}
1521

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

    
1525
	$iflist = get_interface_list();
1526

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

    
1529
	echo <<<EOD
1530

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1770
	conf_mount_rw();
1771

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

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

    
1796
	conf_mount_ro();
1797

    
1798
	return true;
1799
}
1800

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

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

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

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

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

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

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

    
1858
?>
(5-5/27)