Project

General

Profile

Download (36.3 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 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
/* do not load this file twice. */
42
if($config_inc_loaded == true)
43
	return;
44
else
45
	$config_inc_loaded = true;
46

    
47
/* include globals/utility/XML parser files */
48
require_once("globals.inc");
49
require_once("util.inc");
50
require_once("pfsense-utils.inc");
51
require_once("xmlparse.inc");
52

    
53
/* read platform */
54
if (file_exists("{$g['etc_path']}/platform")) {
55
	$g['platform'] = chop(file_get_contents("{$g['etc_path']}/platform"));
56
} else {
57
	$g['platform'] = "unknown";
58
}
59

    
60
/* if our config file exists bail out, we're already set. */
61
if ($g['booting'] and !file_exists($g['cf_conf_path'] . "/config.xml")  ) {
62
	/* find the device where config.xml resides and write out an fstab */
63
	unset($cfgdevice);
64

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

    
68
		if (strstr($g['platform'], "cdrom")) {
69
			/* config is on floppy disk for CD-ROM version */
70
			$cfgdevice = $cfgpartition = "fd0";
71
			$dmesg = `dmesg -a`;
72
			if(ereg("da0", $dmesg) == true) {
73
				$cfgdevice = $cfgpartition = "da0" ;
74
				if (mwexec("/sbin/mount -r /dev/{$cfgdevice} /cf")) {
75
					/* could not mount, fallback to floppy */
76
					$cfgdevice = $cfgpartition = "fd0";
77
				}
78
			}
79
			$cfgfstype = "msdos";
80
			echo "CDROM build\n";
81
			echo "   CFG: {$cfgpartition}\n";
82
			echo "  TYPE: {$cfgfstype}\n";
83
		} else {
84
			/* probe kernel known disks until we find one with config.xml */
85
			$disks = explode(" ", trim(preg_replace("/kern.disks: /", "", exec("/sbin/sysctl kern.disks"))));
86
			foreach ($disks as $mountdisk) {
87
				/* skip mfs mounted filesystems */
88
				if (strstr($mountdisk, "md"))
89
					continue;
90
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}a {$g['cf_path']}") == 0) {
91
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
92
						/* found it */
93
						$cfgdevice = $mountdisk;
94
						$cfgpartition = $cfgdevice . "a";
95
						$cfgfstype = "ufs";
96
						echo "Found configuration on $cfgdevice.\n";
97
					}
98

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

    
101
					if ($cfgdevice)
102
						break;
103
				}
104
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}d {$g['cf_path']}") == 0) {
105
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
106
						/* found it */
107
						$cfgdevice = $mountdisk;
108
						$cfgpartition = $cfgdevice . "d";
109
						$cfgfstype = "ufs";
110
						echo "Found configuration on $cfgdevice.\n";
111
					}
112

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

    
115
					if ($cfgdevice)
116
						break;
117
				}
118
			}
119
		}
120

    
121
		if (!$cfgdevice) {
122
			/* no device found, print an error and die */
123
			echo <<<EOD
124

    
125

    
126
*******************************************************************************
127
* FATAL ERROR                                                                 *
128
* The device that contains the configuration file (config.xml) could not be   *
129
* found. pfSense cannot continue booting.                                     *
130
*******************************************************************************
131

    
132

    
133
EOD;
134

    
135
			mwexec("/sbin/halt");
136
			exit;
137
		}
138

    
139
		/* write device name to a file for rc.firmware */
140
		$fd = fopen("{$g['varetc_path']}/cfdevice", "w");
141
		fwrite($fd, $cfgdevice . "\n");
142
		fclose($fd);
143

    
144
		/* write out an fstab */
145
		$fd = fopen("{$g['etc_path']}/fstab", "w");
146

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

    
150
		fwrite($fd, $fstab);
151
		fclose($fd);
152
	}
153

    
154
	/* mount all filesystems */
155
	mwexec("/sbin/mount -a");
156
}
157

    
158
$config = parse_config();
159

    
160
/****f* config/parse_config
161
 * NAME
162
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
163
 * INPUTS
164
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
165
 * RESULT
166
 *   $config      - array containing all configuration variables
167
 ******/
168
function parse_config($parse = false) {
169
	global $g;
170

    
171
	config_lock();
172
	if(!$parse) {
173
		if(file_exists($g['tmp_path'] . '/config.cache')) {
174
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
175
			if(is_null($config)) {
176
				config_unlock();
177
				parse_config(true);
178
			}
179
		} else {
180
			config_unlock();
181
			$config = parse_config(true);
182
		}
183
	} else {
184
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
185
		generate_config_cache($config);
186
	}
187
	
188
	alias_make_table($config);
189
	config_unlock();
190
	return $config;
191
}
192

    
193
/****f* config/generate_config_cache
194
 * NAME
195
 *   generate_config_cache - Write serialized configuration to cache.
196
 * INPUTS
197
 *   $config	- array containing current firewall configuration
198
 * RESULT
199
 *   boolean	- true on completion
200
 ******/
201
function generate_config_cache($config) {
202
	global $g;
203
	conf_mount_rw();
204
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
205
	fwrite($configcache, serialize($config));
206
	fclose($configcache);
207
	conf_mount_ro();
208
	return true;
209
}
210

    
211
/****f* config/parse_config_bootup
212
 * NAME
213
 *   parse_config_bootup - Bootup-specific configuration checks.
214
 * RESULT
215
 *   null
216
 ******/
217
function parse_config_bootup() {
218
	global $config, $g;
219
	if (!$noparseconfig) {
220
		if (!file_exists("{$g['conf_path']}/config.xml")) {
221
			config_lock();
222
			if ($g['booting']) {
223
				if (strstr($g['platform'], "cdrom")) {
224
					/* try copying the default config. to the floppy */
225
					echo "Resetting factory defaults...\n";
226
					reset_factory_defaults();
227
	
228
					echo "No XML configuration file found - using factory defaults.\n";
229
					echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
230
					echo "file is inserted. If it isn't, your configuration changes will be lost\n";
231
					echo "on reboot.\n";
232
				} else {
233
					echo "XML configuration file not found.  pfSense cannot continue booting.\n";
234
					mwexec("/sbin/halt");
235
					exit;
236
				}
237
			} else {
238
				config_unlock();
239
				exit(0);
240
			}
241
		}
242
	}
243

    
244
	parse_config(true);
245
	
246
	if ((float)$config['version'] > (float)$g['latest_config']) {
247
		echo <<<EOD
248

    
249

    
250
*******************************************************************************
251
* WARNING!                                                                    *
252
* The current configuration has been created with a newer version of pfSense  *
253
* than this one! This can lead to serious misbehavior and even security       *
254
* holes! You are urged to either upgrade to a newer version of pfSense or     *
255
* revert to the default configuration immediately!                            *
256
*******************************************************************************
257

    
258

    
259
EOD;
260
		}
261

    
262
	/* make alias table (for faster lookups) */
263
	alias_make_table($config);
264
	config_unlock();
265
}
266

    
267
/****f* config/conf_mount_rw
268
 * NAME
269
 *   conf_mount_rw - Mount filesystems read/write.
270
 * RESULT
271
 *   null
272
 ******/
273
/* mount flash card read/write */
274
function conf_mount_rw() {
275
	global $g;
276

    
277
	/* do not mount on cdrom platform */
278
	if($g['platform'] == "cdrom")
279
		return;
280

    
281
	/* don't use mount -u anymore
282
	   (doesn't sync the files properly and /bin/sync won't help either) */
283
	$status = mwexec("/sbin/umount -f {$g['cf_path']}");
284

    
285
	$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
286
	if($status <> 0) {
287
		mwexec("/sbin/fsck -y {$g['cf_path']}");
288
		$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
289
	}
290

    
291
	/*    if the platform is soekris or wrap or pfSense, lets mount the
292
	 *    compact flash cards root.
293
         */
294
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
295
	   or $g['platform'] == "embedded") {
296
		mwexec("/sbin/umount -f /");
297
		$status = mwexec("/sbin/mount -w /");
298
		/* we could not mount this correctly.  kick off fsck */
299
		if($status <> 0) {
300
			log_error("File system is dirty.  Launching FSCK for /");
301
			mwexec("/sbin/fsck -y");
302
			$status = mwexec("/sbin/mount -w /");
303
		}
304
	}
305
}
306

    
307
/****f* config/conf_mount_ro
308
 * NAME         
309
 *   conf_mount_ro - Mount filesystems readonly.
310
 * RESULT
311
 *   null        
312
 ******/
313
function conf_mount_ro() {
314
	global $g;
315

    
316
	if($g['booting'] == true)
317
		return;
318
	
319
	/* do not umount if generating ssh keys */
320
	if(file_exists("/tmp/keys_generating"))
321
		return;
322
	
323
	/* do not umount on cdrom platform */
324
	if($g['platform'] == "cdrom")
325
		return;
326

    
327
	mwexec("/sbin/umount -f {$g['cf_path']}");
328
	mwexec("/sbin/mount -r {$g['cf_path']}");
329
	/*    if the platform is soekris or wrap, lets unmount the
330
	 *    compact flash card.
331
         */
332
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
333
	   or $g['platform'] == "embedded") {
334
		mwexec("/sbin/umount -f /");
335
		mwexec("/sbin/mount -f -r /");
336
	}
337
}
338

    
339
/****f* config/convert_config
340
 * NAME         
341
 *   convert_config - Attempt to update config.xml.
342
 * DESCRIPTION
343
 *   convert_config() reads the current global configuration
344
 *   and attempts to convert it to conform to the latest
345
 *   config.xml version. This allows major formatting changes
346
 *   to be made with a minimum of breakage.
347
 * RESULT
348
 *   null        
349
 ******/
350
/* convert configuration, if necessary */
351
function convert_config() {
352
	global $config, $g;
353

    
354
	if ($config['version'] == $g['latest_config'])
355
		return;		/* already at latest version */
356

    
357
	// Save off config version
358
	$prev_version = $config['version'];
359

    
360
	/* convert 1.0 -> 1.1 */
361
	if ($config['version'] == "1.0") {
362
		$opti = 1;
363
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
364

    
365
		/* convert DMZ to optional, if necessary */
366
		if (isset($config['interfaces']['dmz'])) {
367

    
368
			$dmzcfg = &$config['interfaces']['dmz'];
369

    
370
			if ($dmzcfg['if']) {
371
				$config['interfaces']['opt' . $opti] = array();
372
				$optcfg = &$config['interfaces']['opt' . $opti];
373

    
374
				$optcfg['enable'] = $dmzcfg['enable'];
375
				$optcfg['descr'] = "DMZ";
376
				$optcfg['if'] = $dmzcfg['if'];
377
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
378
				$optcfg['subnet'] = $dmzcfg['subnet'];
379

    
380
				$ifmap['dmz'] = "opt" . $opti;
381
				$opti++;
382
			}
383

    
384
			unset($config['interfaces']['dmz']);
385
		}
386

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

    
390
			if (!$config['interfaces']['wlan' . $i]['if']) {
391
				unset($config['interfaces']['wlan' . $i]);
392
				continue;
393
			}
394

    
395
			$wlancfg = &$config['interfaces']['wlan' . $i];
396
			$config['interfaces']['opt' . $opti] = array();
397
			$optcfg = &$config['interfaces']['opt' . $opti];
398

    
399
			$optcfg['enable'] = $wlancfg['enable'];
400
			$optcfg['descr'] = "WLAN" . $i;
401
			$optcfg['if'] = $wlancfg['if'];
402
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
403
			$optcfg['subnet'] = $wlancfg['subnet'];
404
			$optcfg['bridge'] = $wlancfg['bridge'];
405

    
406
			$optcfg['wireless'] = array();
407
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
408
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
409
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
410
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
411

    
412
			$ifmap['wlan' . $i] = "opt" . $opti;
413

    
414
			unset($config['interfaces']['wlan' . $i]);
415
			$opti++;
416
		}
417

    
418
		/* convert filter rules */
419
		$n = count($config['filter']['rule']);
420
		for ($i = 0; $i < $n; $i++) {
421

    
422
			$fr = &$config['filter']['rule'][$i];
423

    
424
			/* remap interface */
425
			if (array_key_exists($fr['interface'], $ifmap))
426
				$fr['interface'] = $ifmap[$fr['interface']];
427
			else {
428
				/* remove the rule */
429
				echo "\nWarning: filter rule removed " .
430
					"(interface '{$fr['interface']}' does not exist anymore).";
431
				unset($config['filter']['rule'][$i]);
432
				continue;
433
			}
434

    
435
			/* remap source network */
436
			if (isset($fr['source']['network'])) {
437
				if (array_key_exists($fr['source']['network'], $ifmap))
438
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
439
				else {
440
					/* remove the rule */
441
					echo "\nWarning: filter rule removed " .
442
						"(source network '{$fr['source']['network']}' does not exist anymore).";
443
					unset($config['filter']['rule'][$i]);
444
					continue;
445
				}
446
			}
447

    
448
			/* remap destination network */
449
			if (isset($fr['destination']['network'])) {
450
				if (array_key_exists($fr['destination']['network'], $ifmap))
451
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
452
				else {
453
					/* remove the rule */
454
					echo "\nWarning: filter rule removed " .
455
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
456
					unset($config['filter']['rule'][$i]);
457
					continue;
458
				}
459
			}
460
		}
461

    
462
		/* convert shaper rules */
463
		$n = count($config['pfqueueing']['rule']);
464
		if (is_array($config['pfqueueing']['rule']))
465
			for ($i = 0; $i < $n; $i++) {
466

    
467
			$fr = &$config['pfqueueing']['rule'][$i];
468

    
469
			/* remap interface */
470
			if (array_key_exists($fr['interface'], $ifmap))
471
				$fr['interface'] = $ifmap[$fr['interface']];
472
			else {
473
				/* remove the rule */
474
				echo "\nWarning: traffic shaper rule removed " .
475
					"(interface '{$fr['interface']}' does not exist anymore).";
476
				unset($config['pfqueueing']['rule'][$i]);
477
				continue;
478
			}
479

    
480
			/* remap source network */
481
			if (isset($fr['source']['network'])) {
482
				if (array_key_exists($fr['source']['network'], $ifmap))
483
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
484
				else {
485
					/* remove the rule */
486
					echo "\nWarning: traffic shaper rule removed " .
487
						"(source network '{$fr['source']['network']}' does not exist anymore).";
488
					unset($config['pfqueueing']['rule'][$i]);
489
					continue;
490
				}
491
			}
492

    
493
			/* remap destination network */
494
			if (isset($fr['destination']['network'])) {
495
				if (array_key_exists($fr['destination']['network'], $ifmap))
496
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
497
				else {
498
					/* remove the rule */
499
					echo "\nWarning: traffic shaper rule removed " .
500
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
501
					unset($config['pfqueueing']['rule'][$i]);
502
					continue;
503
				}
504
			}
505
		}
506

    
507
		$config['version'] = "1.1";
508
	}
509

    
510
	/* convert 1.1 -> 1.2 */
511
	if ($config['version'] == "1.1") {
512
		/* move LAN DHCP server config */
513
		$tmp = $config['dhcpd'];
514
		$config['dhcpd'] = array();
515
		$config['dhcpd']['lan'] = $tmp;
516

    
517
		/* encrypt password */
518
		$config['system']['password'] = crypt($config['system']['password']);
519

    
520
		$config['version'] = "1.2";
521
	}
522

    
523
	/* convert 1.2 -> 1.3 */
524
	if ($config['version'] == "1.2") {
525
		/* convert advanced outbound NAT config */
526
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
527
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
528
			$src = $curent['source'];
529
			$curent['source'] = array();
530
			$curent['source']['network'] = $src;
531
			$curent['destination'] = array();
532
			$curent['destination']['any'] = true;
533
		}
534

    
535
		/* add an explicit type="pass" to all filter rules to make things consistent */
536
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
537
			$config['filter']['rule'][$i]['type'] = "pass";
538
		}
539

    
540
		$config['version'] = "1.3";
541
	}
542

    
543
	/* convert 1.3 -> 1.4 */
544
	if ($config['version'] == "1.3") {
545
		/* convert shaper rules (make pipes) */
546
		if (is_array($config['pfqueueing']['rule'])) {
547
			$config['pfqueueing']['pipe'] = array();
548

    
549
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
550
				$curent = &$config['pfqueueing']['rule'][$i];
551

    
552
				/* make new pipe and associate with this rule */
553
				$newpipe = array();
554
				$newpipe['descr'] = $curent['descr'];
555
				$newpipe['bandwidth'] = $curent['bandwidth'];
556
				$newpipe['delay'] = $curent['delay'];
557
				$newpipe['mask'] = $curent['mask'];
558
				$config['pfqueueing']['pipe'][$i] = $newpipe;
559

    
560
				$curent['targetpipe'] = $i;
561

    
562
				unset($curent['bandwidth']);
563
				unset($curent['delay']);
564
				unset($curent['mask']);
565
			}
566
		}
567

    
568
		$config['version'] = "1.4";
569
	}
570

    
571
	/* Convert 1.4 -> 1.5 */
572
	if ($config['version'] == "1.4") {
573

    
574
		/* Default route moved */
575
		if (isset($config['interfaces']['wan']['gateway']))
576
			if ($config['interfaces']['wan']['gateway'] <> "")
577
				$config['system']['gateway'] = $config['interfaces']['wan']['gateway'];
578
		unset($config['interfaces']['wan']['gateway']);
579

    
580
                /* Queues are no longer interface specific */
581
                if (isset($config['interfaces']['lan']['schedulertype']))
582
                        unset($config['interfaces']['lan']['schedulertype']);
583
                if (isset($config['interfaces']['wan']['schedulertype']))
584
                        unset($config['interfaces']['wan']['schedulertype']);
585

    
586
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
587
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
588
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
589
                }
590

    
591
		$config['version'] = "1.5";
592
	}
593

    
594
	/* Convert 1.5 -> 1.6 */
595
	if ($config['version'] == "1.5") {
596
		/* Alternate firmware URL moved */
597
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
598
			$config['system']['alt_firmware_url'] = array();
599
			$config['system']['alt_firmware_url']['enabled'] = "";
600
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
601
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
602
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
603
		} else {
604
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
605
		}
606

    
607
		$config['version'] = "1.6";
608
	}
609
	
610
	/* Convert 1.6 -> 1.7 */
611
	if ($config['version'] == "1.6") {
612
		/* wipe previous shaper configuration */
613
		unset($config['shaper']['queue']);
614
		unset($config['shaper']['rule']);
615
		unset($config['interfaces']['wan']['bandwidth']);
616
		unset($config['interfaces']['wan']['bandwidthtype']);
617
		unset($config['interfaces']['lan']['bandwidth']);
618
		unset($config['interfaces']['lan']['bandwidthtype']);		
619
		$config['shaper']['enable'] = FALSE;
620
		$config['version'] = "1.7";	
621
	}
622
	/* Convert 1.7 -> 1.8 */
623
	if ($config['version'] == "1.7") {
624
		if(isset($config['proxyarp']) && is_array($config['proxyarp']['proxyarpnet'])) {
625
			$proxyarp = &$config['proxyarp']['proxyarpnet'];
626
			foreach($proxyarp as $arpent){
627
				$vip = array();
628
				$vip['mode'] = "proxyarp";
629
				$vip['interface'] = $arpent['interface'];
630
				$vip['descr'] = $arpent['descr'];
631
				if (isset($arpent['range'])) {
632
					$vip['range'] = $arpent['range'];
633
					$vip['type'] = "range";
634
				} else {
635
					$subnet = explode('/', $arpent['network']);
636
					$vip['subnet'] = $subnet[0];
637
					if (isset($subnet[1])) {
638
						$vip['subnet_bits'] = $subnet[1];
639
						$vip['type'] = "network";
640
					} else {
641
						$vip['subnet_bits'] = "32";
642
						$vip['type'] = "single";
643
					}
644
				}
645
				$config['virtualip']['vip'][] = $vip;
646
			}
647
			unset($config['proxyarp']);
648
		}
649
		if(isset($config['installedpackages']) && isset($config['installedpackages']['carp']) && is_array($config['installedpackages']['carp']['config'])) {
650
			$carp = &$config['installedpackages']['carp']['config'];
651
			foreach($carp as $carpent){
652
				$vip = array();
653
				$vip['mode'] = "carp";
654
				$vip['interface'] = "AUTO";
655
				$vip['descr'] = "CARP vhid {$carpent['vhid']}";
656
				$vip['type'] = "single";
657
				$vip['vhid'] = $carpent['vhid'];
658
				$vip['advskew'] = $carpent['advskew'];
659
				$vip['password'] = $carpent['password'];
660
				$vip['subnet'] = $carpent['ipaddress'];
661
				$vip['subnet_bits'] = $carpent['netmask'];
662
				$config['virtualip']['vip'][] = $vip;
663
			}
664
			unset($config['installedpackages']['carp']);
665
		}
666
		/* Server NAT is no longer needed */
667
		unset($config['nat']['servernat']);
668
		
669
		/* enable SSH */
670
		if ($config['version'] == "1.8") {
671
			$config['system']['sshenabled'] = true;
672
		}
673
		
674
		$config['version'] = "1.9";
675
	}
676

    
677
	/* Convert 1.8 -> 1.9 */
678
	if ($config['version'] == "1.8") {
679
		$config['theme']="metallic";
680
		$config['version'] = "1.9";
681
	}
682
	/* Convert 1.9 -> 2.0 */
683
	if ($config['version'] == "1.9") {
684
		if(is_array($config['ipsec']['tunnel'])) {
685
			reset($config['ipsec']['tunnel']);
686
			while (list($index, $tunnel) = each($config['ipsec']['tunnel'])) {
687
				/* Sanity check on required variables */
688
				/* This fixes bogus <tunnel> entries - remnant of bug #393 */
689
				if (!isset($tunnel['local-subnet']) && !isset($tunnel['remote-subnet'])) {
690
					unset($config['ipsec']['tunnel'][$tunnel]);
691
				}
692
			}
693
        	}
694
		$config['version'] = "2.0";
695
	}
696
	/* Convert 2.0 -> 2.1 */
697
	if ($config['version'] == "2.0") {
698
		/* shaper scheduler moved */
699
		if(isset($config['system']['schedulertype'])) {
700
			$config['shaper']['schedulertype'] = $config['system']['schedulertype'];
701
			unset($config['system']['schedulertype']);
702
		}
703
		$config['version'] = "2.1";
704
	}
705

    
706

    
707
	if ($prev_version != $config['version'])
708
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
709
}
710

    
711
/****f* config/write_config
712
 * NAME
713
 *   write_config - Backup and write the firewall configuration.
714
 * DESCRIPTION
715
 *   write_config() handles backing up the current configuration,
716
 *   applying changes, and regenerating the configuration cache.
717
 * INPUTS
718
 *   $desc	- string containing the a description of configuration changes
719
 *   $backup	- boolean: do not back up current configuration if false.
720
 * RESULT
721
 *   null       
722
 ******/
723
/* save the system configuration */
724
function write_config($desc="Unknown", $backup = true) {
725
	global $config, $g;
726

    
727
	if($g['platform'] <> "wrap") {
728
		if($backup) backup_config();
729
	}
730

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

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

    
738
	$config['revision']['description'] = $desc;
739
	$config['revision']['time'] = $changetime;
740
	
741
	config_lock();
742
	conf_mount_rw();
743

    
744
	/* generate configuration XML */
745
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
746

    
747
	/* write new configuration */
748
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
749
	if (!$fd)
750
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
751
	fwrite($fd, $xmlconfig);
752
	fclose($fd);
753

    
754
	if($g['booting'] <> true) {
755
		conf_mount_ro();
756
	}
757

    
758
	config_unlock();
759

    
760
	// Always reparse the config after it's written - something is getting lost in serialize().
761
	$config = parse_config(true);
762
	return $config;
763
}
764

    
765
/****f* config/reset_factory_defaults
766
 * NAME
767
 *   reset_factory_defaults - Reset the system to its default configuration.
768
 * RESULT
769
 *   integer	- indicates completion
770
 ******/
771
function reset_factory_defaults() {
772
	global $g;
773

    
774
	config_lock();
775
	conf_mount_rw();
776

    
777
	/* create conf directory, if necessary */
778
	safe_mkdir("{$g['cf_conf_path']}");
779

    
780
	/* clear out /conf */
781
	$dh = opendir($g['conf_path']);
782
	while ($filename = readdir($dh)) {
783
		if (($filename != ".") && ($filename != "..")) {
784
			unlink_if_exists($g['conf_path'] . "/" . $filename);
785
		}
786
	}
787
	closedir($dh);
788

    
789
	/* copy default configuration */
790
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
791
	
792
	/* call the wizard */
793
	touch("/trigger_initial_wizard");
794
	
795
	conf_mount_ro();
796
	config_unlock();
797

    
798
	return 0;
799
}
800

    
801
function config_restore($conffile) {
802
	global $config, $g;
803
       
804
        if (!file_exists($conffile))
805
                return 1;
806
        
807
        config_lock();
808
        conf_mount_rw();        
809
        
810
        backup_config();
811
        copy($conffile, "{$g['cf_conf_path']}/config.xml");
812
	$config = parse_config(true);
813
        write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
814
        
815
        conf_mount_ro();
816
        config_unlock();
817

    
818
        return 0;
819
}
820

    
821

    
822

    
823
function config_install($conffile) {
824
        global $config, $g;
825
        
826
        if (!file_exists($conffile))
827
                return 1;
828

    
829
	if($g['booting'] == true)
830
		echo "Installing configuration...\n";
831
 
832
        config_lock();
833
        conf_mount_rw();
834
        
835
        copy($conffile, "{$g['conf_path']}/config.xml");
836
                
837
        conf_mount_ro();
838
        config_unlock();
839

    
840
        return 0;
841
}
842

    
843
/* lock configuration file, decide that the lock file is stale after
844
   10 seconds */
845
function config_lock() {
846
	global $g, $process_lock;
847

    
848
	/* No need to continue if we're the ones holding the lock */
849
	if ($process_lock)
850
		return;
851

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

    
854
	$n = 0;
855
	while ($n < 10) {
856
		/* open the lock file in append mode to avoid race condition */
857
		if ($fd = @fopen($lockfile, "x")) {
858
			/* succeeded */
859
			$process_lock = true;
860
			fclose($fd);
861
			return;
862
		} else {
863
			/* file locked, wait and try again */
864
			$process_lock = false;
865
			sleep(1);
866
			$n++;
867
		}
868
	}
869
}
870

    
871
/* unlock configuration file */
872
function config_unlock() {
873
	global $g, $process_lock;
874

    
875
	$lockfile = "{$g['varrun_path']}/config.lock";
876
	$process_lock = false;
877

    
878
	unlink_if_exists($lockfile);
879
}
880

    
881
function set_networking_interfaces_ports() {
882
	global $noreboot;
883
	global $config;
884
	global $g;
885
	global $fp;
886

    
887
	$fp = fopen('php://stdin', 'r');
888

    
889
	$iflist = get_interface_list();
890

    
891
	echo <<<EOD
892

    
893
Valid interfaces are:
894

    
895

    
896
EOD;
897

    
898
	foreach ($iflist as $iface => $ifa) {
899
		echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
900
			$ifa['up'] ? "   (up)" : "");
901
	}
902

    
903
	echo <<<EOD
904

    
905
Do you want to set up VLANs first?
906
If you are not going to use VLANs, or only for optional interfaces, you
907
should say no here and use the webGUI to configure VLANs later, if required.
908

    
909
Do you want to set up VLANs now [y|n]?
910
EOD;
911

    
912
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
913
		vlan_setup();
914

    
915
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
916

    
917
		echo "\n\nVLAN interfaces:\n\n";
918
		$i = 0;
919
		foreach ($config['vlans']['vlan'] as $vlan) {
920

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

    
924
			$iflist['vlan' . $i] = array();
925
			$i++;
926
		}
927
	}
928

    
929
	echo <<<EOD
930

    
931
*NOTE*  pfSense requires *ATLEAST* 2 assigned interfaces to function.
932
        If you do not have two interfaces turn off the machine until
933
	you do.
934

    
935
If you do not know the names of your interfaces, you may choose to use
936
auto-detection... In that case, disconnect all interfaces now before
937
hitting a.   The system will then prompt you to plug in each nic to
938
autodetect.
939

    
940
EOD;
941

    
942
	do {
943
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
944
		$lanif = chop(fgets($fp));
945
		if ($lanif === "") {
946
			exit(0);
947
		}
948

    
949
		if ($lanif === "a")
950
			$lanif = autodetect_interface("LAN", $fp);
951
		else if (!array_key_exists($lanif, $iflist)) {
952
			echo "\nInvalid interface name '{$lanif}'\n";
953
			unset($lanif);
954
			continue;
955
		}
956
	} while (!$lanif);
957

    
958
	do {
959
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
960
		$wanif = chop(fgets($fp));
961
		if ($wanif === "") {
962
			exit(0);
963
		}
964
		if ($wanif === "a")
965
			$wanif = autodetect_interface("WAN", $fp);
966
		else if (!array_key_exists($wanif, $iflist)) {
967
			echo "\nInvalid interface name '{$wanif}'\n";
968
			unset($wanif);
969
			continue;
970
		}
971
	} while (!$wanif);
972

    
973
	/* optional interfaces */
974
	$i = 0;
975
	$optif = array();
976

    
977
	while (1) {
978
		if ($optif[$i])
979
			$i++;
980
		$i1 = $i + 1;
981
		echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
982
			"(or nothing if finished): ";
983
		$optif[$i] = chop(fgets($fp));
984

    
985
		if ($optif[$i]) {
986
			if ($optif[$i] === "a") {
987
				$ad = autodetect_interface("Optional " . $i1, $fp);
988
				if ($ad)
989
					$optif[$i] = $ad;
990
				else
991
					unset($optif[$i]);
992
			} else if (!array_key_exists($optif[$i], $iflist)) {
993
				echo "\nInvalid interface name '{$optif[$i]}'\n";
994
				unset($optif[$i]);
995
				continue;
996
			}
997
		} else {
998
			unset($optif[$i]);
999
			break;
1000
		}
1001
	}
1002

    
1003
	/* check for double assignments */
1004
	$ifarr = array_merge(array($lanif, $wanif), $optif);
1005

    
1006
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
1007
		for ($j = ($i+1); $j < count($ifarr); $j++) {
1008
			if ($ifarr[$i] == $ifarr[$j]) {
1009
				echo <<<EOD
1010

    
1011
Error: you cannot assign the same interface name twice!
1012

    
1013
EOD;
1014

    
1015
				exit(0);
1016
			}
1017
		}
1018
	}
1019

    
1020
	echo <<<EOD
1021

    
1022
The interfaces will be assigned as follows:
1023

    
1024
LAN  -> {$lanif}
1025
WAN  -> {$wanif}
1026

    
1027
EOD;
1028

    
1029
	for ($i = 0; $i < count($optif); $i++) {
1030
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
1031
	}
1032

    
1033
	if(!$noreboot) echo "\npfSense will reboot after saving the changes.\n";
1034

    
1035
echo <<<EOD
1036

    
1037
Do you want to proceed [y|n]?
1038
EOD;
1039

    
1040
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
1041

    
1042
		$config['interfaces']['lan']['if'] = $lanif;
1043
		if (preg_match($g['wireless_regex'], $lanif)) {
1044
			if (!is_array($config['interfaces']['lan']['wireless']))
1045
				$config['interfaces']['lan']['wireless'] = array();
1046
		} else {
1047
			unset($config['interfaces']['lan']['wireless']);
1048
		}
1049
		
1050
		$config['interfaces']['wan']['if'] = $wanif;
1051
		if (preg_match($g['wireless_regex'], $wanif)) {
1052
			if (!is_array($config['interfaces']['wan']['wireless']))
1053
				$config['interfaces']['wan']['wireless'] = array();
1054
		} else {
1055
			unset($config['interfaces']['wan']['wireless']);
1056
		}
1057
		
1058
		for ($i = 0; $i < count($optif); $i++) {
1059
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1060
				$config['interfaces']['opt' . ($i+1)] = array();
1061
			
1062
			$config['interfaces']['opt' . ($i+1)]['if'] = $optif[$i];
1063
			
1064
			/* wireless interface? */
1065
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1066
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1067
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1068
			} else {
1069
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1070
			}
1071
			
1072
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1073
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1074
		}
1075
		
1076
		/* remove all other (old) optional interfaces */
1077
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1078
			unset($config['interfaces']['opt' . ($i+1)]);
1079
		
1080
		conf_mount_rw();
1081
		
1082
		/* call the wizard */
1083
		touch("/trigger_initial_wizard");
1084
		
1085
		write_config();
1086
		
1087
		echo <<<EOD
1088

    
1089

    
1090

    
1091
EOD;
1092

    
1093
		if($noreboot <> true)
1094
			system_reboot_sync();
1095
	}
1096
}
1097

    
1098
function autodetect_interface($ifname, $fp) {
1099
	$iflist_prev = get_interface_list("media");
1100
	echo <<<EOD
1101

    
1102
Connect the {$ifname} interface now and make sure that the link is up.
1103
Then press ENTER to continue.
1104

    
1105
EOD;
1106
	fgets($fp);
1107
	$iflist = get_interface_list("media");
1108

    
1109
	foreach ($iflist_prev as $ifn => $ifa) {
1110
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1111
			echo "Detected link-up on interface {$ifn}.\n";
1112
			return $ifn;
1113
		}
1114
	}
1115

    
1116
	echo "No link-up detected.\n";
1117

    
1118
	return null;
1119
}
1120

    
1121
function vlan_setup() {
1122
	global $iflist, $config, $g, $fp;
1123

    
1124
	$iflist = get_interface_list();
1125

    
1126
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1127

    
1128
	echo <<<EOD
1129

    
1130
WARNING: all existing VLANs will be cleared if you proceed!
1131

    
1132
Do you want to proceed [y|n]?
1133
EOD;
1134

    
1135
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1136
		return;
1137
	}
1138

    
1139
	$config['vlans']['vlan'] = array();
1140
	echo "\n";
1141

    
1142
	while (1) {
1143
		$vlan = array();
1144

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

    
1148
		if ($vlan['if']) {
1149
			if (!array_key_exists($vlan['if'], $iflist) or
1150
			    !is_jumbo_capable($vlan['if'])) {
1151
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1152
				continue;
1153
			}
1154
		} else {
1155
			break;
1156
		}
1157

    
1158
		echo "Enter the VLAN tag (1-4094): ";
1159
		$vlan['tag'] = chop(fgets($fp));
1160

    
1161
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1162
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1163
			continue;
1164
		}
1165

    
1166
		$config['vlans']['vlan'][] = $vlan;
1167
	}
1168
}
1169

    
1170
function system_start_ftp_helpers() {
1171
	require_once("interfaces.inc");
1172
	global $config, $g;
1173

    
1174
	/* if the ftp proxy is disabled then killall pftpx and return */	
1175
	if($config['system']['disableftpproxy'] <> "") {
1176
		mwexec("/usr/bin/killall pftpx");
1177
		return;
1178
	}
1179
	
1180
	/* grab the current WAN IP address */
1181
	$wanip = get_current_wan_address();
1182
	
1183
	/* kill off pftpx if its already running */
1184
	if(is_process_running("pftpx"))
1185
		mwexec("/usr/bin/killall pftpx 2>/dev/null");
1186

    
1187
	/* if we do not have a wanip, launch with just the -g flag */	
1188
	if($wanip <> "") {
1189
		$command = "/usr/local/sbin/pftpx -g 8021 {$wanip}";
1190
		mwexec($command);
1191
	} else {
1192
		mwexec("/usr/local/sbin/pftpx -g 8021");
1193
	}
1194
}
1195

    
1196
function cleanup_backupcache($revisions = 30) {
1197
	global $g;
1198
	$i = false;
1199
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1200
		conf_mount_rw();
1201
		$backups = get_backups();
1202
		$newbaks = array();
1203
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1204
		$baktimes = $backups['versions'];
1205
		$tocache = array();
1206
		unset($backups['versions']);
1207
       		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1208
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));	
1209
                	if(!in_array($tocheck, $baktimes)) {
1210
				$i = true;
1211
				if($bootup) print " " . $tocheck . "a";
1212
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1213
				if($newxml['revision']['description'] == "") $newxml['revision']['description'] = "Unknown";
1214
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1215
			}
1216
        	}
1217
		foreach($backups as $checkbak) {
1218
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1219
				$newbaks[] = $checkbak;
1220
			} else {
1221
				$i = true;
1222
				if($bootup) print " " . $tocheck . "r";
1223
			}
1224
		}
1225
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);	
1226
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1227
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1228
			foreach($toslice as $sliced) $newcache[$sliced] = $tocache[$sliced];
1229
			foreach($tocache as $version => $versioninfo) {
1230
				if(!in_array($version, array_keys($newcache))) {
1231
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1232
					if($bootup) print " " . $tocheck . "d";
1233
				}
1234
			}
1235
			$tocache = $newcache;
1236
		}
1237
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1238
        	fwrite($bakout, serialize($tocache));
1239
  	        fclose($bakout);
1240
		conf_mount_ro();
1241
	}
1242
	if($g['booting']) {
1243
		if($i) {
1244
			print "done.\n";
1245
		}
1246
	}
1247
}
1248
  	 
1249
function get_backups() { 	 
1250
	global $g;
1251

    
1252
        if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1253
                $confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1254
		$bakvers = array_keys($confvers);
1255
		$toreturn = array();
1256
		sort($bakvers);
1257
		// $bakvers = array_reverse($bakvers);
1258
		foreach(array_reverse($bakvers) as $bakver) $toreturn[] = array('time' => $bakver,
1259
								 'description' => $confvers[$bakver]['description']
1260
								);
1261
        } else { 	 
1262
                return false; 	 
1263
        }
1264
	$toreturn['versions'] = $bakvers;
1265
        return $toreturn;
1266
}
1267

    
1268
function backup_config() {
1269
	global $config, $g;
1270

    
1271
	if($g['platform'] == "cdrom")
1272
		return;
1273

    
1274
	conf_mount_rw();
1275

    
1276
	/* Create backup directory if needed */
1277
	safe_mkdir("{$g['cf_conf_path']}/backup");
1278

    
1279
        if($config['revision']['time'] == "") {
1280
                $baktime = 0;
1281
        } else {
1282
                $baktime = $config['revision']['time'];
1283
        }
1284
        if($config['revision']['description'] == "") {
1285
                $bakdesc = "Unknown";
1286
        } else {
1287
                $bakdesc = $config['revision']['description'];
1288
        }
1289
        copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1290
        if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1291
                $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1292
        } else {
1293
                $backupcache = array();
1294
        }
1295
        $backupcache[$baktime] = array('description' => $bakdesc);
1296
        $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1297
        fwrite($bakout, serialize($backupcache));
1298
        fclose($bakout);
1299
	
1300
	conf_mount_ro();
1301
	
1302
	return true;
1303
}
1304

    
1305
function mute_kernel_msgs() {
1306
	exec("/sbin/conscontrol mute on");
1307
}
1308

    
1309
function unmute_kernel_msgs() {
1310
	exec("/sbin/conscontrol mute off");
1311
}
1312

    
1313
function start_devd() {
1314
	exec("/sbin/devd");
1315
}
1316

    
1317
?>
(3-3/24)