Project

General

Profile

Download (32 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", $desg) == true) {
73
				$cfgdevice = $cfgpartition = "da0" ;
74
				if (mwexec("/sbin/mount -r da0 /cf") <> 0) {
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
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
204
	fwrite($configcache, serialize($config));
205
	fclose($configcache);
206
	return true;
207
}
208

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

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

    
247

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

    
256

    
257
EOD;
258
		}
259

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

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

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

    
279
	/* don't use mount -u anymore
280
	   (doesn't sync the files properly and /bin/sync won't help either) */
281
	mwexec("/sbin/umount -f {$g['cf_path']}");
282
	$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
283
	while($status == -1) {
284
		mwexec("fsck -y");
285
		$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
286
	}
287
	/* if the platform is soekris or wrap, lets mount the
288
	   compact flash card. */
289
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx") {
290
		mwexec("/sbin/umount -f {$g['embeddedbootupslice']}");
291
		mwexec("/sbin/mount -w {$g['embeddedbootupslice']}");
292
	}
293
}
294

    
295
/****f* config/conf_mount_ro
296
 * NAME         
297
 *   conf_mount_ro - Mount filesystems readonly.
298
 * RESULT
299
 *   null        
300
 ******/
301
function conf_mount_ro() {
302
	global $g, $do_not_mount_ro;
303

    
304
	if($g['booting'] == true) return;
305
	
306
	/* do not umount on cdrom platform */
307
	if($g['platform'] == "cdrom")
308
		return;	
309

    
310
	mwexec("/sbin/umount -f {$g['cf_path']}");
311
	mwexec("/sbin/mount -r {$g['cf_path']}");
312
	/* if the platform is soekris or wrap, lets unmount the
313
	   compact flash card. */
314
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx") {
315
		mwexec("/sbin/umount -f {$g['embeddedbootupslice']}");
316
		mwexec("/sbin/mount -r {$g['embeddedbootupslice']}");
317
	}
318
}
319

    
320
/****f* config/convert_config
321
 * NAME         
322
 *   convert_config - Attempt to update config.xml.
323
 * DESCRIPTION
324
 *   convert_config() reads the current global configuration
325
 *   and attempts to convert it to conform to the latest
326
 *   config.xml version. This allows major formatting changes
327
 *   to be made with a minimum of breakage.
328
 * RESULT
329
 *   null        
330
 ******/
331
/* convert configuration, if necessary */
332
function convert_config() {
333
	global $config, $pkg_config, $g;
334

    
335
	if ($config['version'] == $g['latest_config'])
336
		return;		/* already at latest version */
337

    
338
	// Save off config version
339
	$prev_version = $config['version'];
340

    
341
	/* convert 1.0 -> 1.1 */
342
	if ($config['version'] == "1.0") {
343
		$opti = 1;
344
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
345

    
346
		/* convert DMZ to optional, if necessary */
347
		if (isset($config['interfaces']['dmz'])) {
348

    
349
			$dmzcfg = &$config['interfaces']['dmz'];
350

    
351
			if ($dmzcfg['if']) {
352
				$config['interfaces']['opt' . $opti] = array();
353
				$optcfg = &$config['interfaces']['opt' . $opti];
354

    
355
				$optcfg['enable'] = $dmzcfg['enable'];
356
				$optcfg['descr'] = "DMZ";
357
				$optcfg['if'] = $dmzcfg['if'];
358
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
359
				$optcfg['subnet'] = $dmzcfg['subnet'];
360

    
361
				$ifmap['dmz'] = "opt" . $opti;
362
				$opti++;
363
			}
364

    
365
			unset($config['interfaces']['dmz']);
366
		}
367

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

    
371
			if (!$config['interfaces']['wlan' . $i]['if']) {
372
				unset($config['interfaces']['wlan' . $i]);
373
				continue;
374
			}
375

    
376
			$wlancfg = &$config['interfaces']['wlan' . $i];
377
			$config['interfaces']['opt' . $opti] = array();
378
			$optcfg = &$config['interfaces']['opt' . $opti];
379

    
380
			$optcfg['enable'] = $wlancfg['enable'];
381
			$optcfg['descr'] = "WLAN" . $i;
382
			$optcfg['if'] = $wlancfg['if'];
383
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
384
			$optcfg['subnet'] = $wlancfg['subnet'];
385
			$optcfg['bridge'] = $wlancfg['bridge'];
386

    
387
			$optcfg['wireless'] = array();
388
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
389
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
390
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
391
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
392

    
393
			$ifmap['wlan' . $i] = "opt" . $opti;
394

    
395
			unset($config['interfaces']['wlan' . $i]);
396
			$opti++;
397
		}
398

    
399
		/* convert filter rules */
400
		$n = count($config['filter']['rule']);
401
		for ($i = 0; $i < $n; $i++) {
402

    
403
			$fr = &$config['filter']['rule'][$i];
404

    
405
			/* remap interface */
406
			if (array_key_exists($fr['interface'], $ifmap))
407
				$fr['interface'] = $ifmap[$fr['interface']];
408
			else {
409
				/* remove the rule */
410
				echo "\nWarning: filter rule removed " .
411
					"(interface '{$fr['interface']}' does not exist anymore).";
412
				unset($config['filter']['rule'][$i]);
413
				continue;
414
			}
415

    
416
			/* remap source network */
417
			if (isset($fr['source']['network'])) {
418
				if (array_key_exists($fr['source']['network'], $ifmap))
419
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
420
				else {
421
					/* remove the rule */
422
					echo "\nWarning: filter rule removed " .
423
						"(source network '{$fr['source']['network']}' does not exist anymore).";
424
					unset($config['filter']['rule'][$i]);
425
					continue;
426
				}
427
			}
428

    
429
			/* remap destination network */
430
			if (isset($fr['destination']['network'])) {
431
				if (array_key_exists($fr['destination']['network'], $ifmap))
432
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
433
				else {
434
					/* remove the rule */
435
					echo "\nWarning: filter rule removed " .
436
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
437
					unset($config['filter']['rule'][$i]);
438
					continue;
439
				}
440
			}
441
		}
442

    
443
		/* convert shaper rules */
444
		$n = count($config['pfqueueing']['rule']);
445
		if (is_array($config['pfqueueing']['rule']))
446
			for ($i = 0; $i < $n; $i++) {
447

    
448
			$fr = &$config['pfqueueing']['rule'][$i];
449

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

    
461
			/* remap source network */
462
			if (isset($fr['source']['network'])) {
463
				if (array_key_exists($fr['source']['network'], $ifmap))
464
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
465
				else {
466
					/* remove the rule */
467
					echo "\nWarning: traffic shaper rule removed " .
468
						"(source network '{$fr['source']['network']}' does not exist anymore).";
469
					unset($config['pfqueueing']['rule'][$i]);
470
					continue;
471
				}
472
			}
473

    
474
			/* remap destination network */
475
			if (isset($fr['destination']['network'])) {
476
				if (array_key_exists($fr['destination']['network'], $ifmap))
477
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
478
				else {
479
					/* remove the rule */
480
					echo "\nWarning: traffic shaper rule removed " .
481
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
482
					unset($config['pfqueueing']['rule'][$i]);
483
					continue;
484
				}
485
			}
486
		}
487

    
488
		$config['version'] = "1.1";
489
	}
490

    
491
	/* convert 1.1 -> 1.2 */
492
	if ($config['version'] == "1.1") {
493
		/* move LAN DHCP server config */
494
		$tmp = $config['dhcpd'];
495
		$config['dhcpd'] = array();
496
		$config['dhcpd']['lan'] = $tmp;
497

    
498
		/* encrypt password */
499
		$config['system']['password'] = crypt($config['system']['password']);
500

    
501
		$config['version'] = "1.2";
502
	}
503

    
504
	/* convert 1.2 -> 1.3 */
505
	if ($config['version'] == "1.2") {
506
		/* convert advanced outbound NAT config */
507
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
508
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
509
			$src = $curent['source'];
510
			$curent['source'] = array();
511
			$curent['source']['network'] = $src;
512
			$curent['destination'] = array();
513
			$curent['destination']['any'] = true;
514
		}
515

    
516
		/* add an explicit type="pass" to all filter rules to make things consistent */
517
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
518
			$config['filter']['rule'][$i]['type'] = "pass";
519
		}
520

    
521
		$config['version'] = "1.3";
522
	}
523

    
524
	/* convert 1.3 -> 1.4 */
525
	if ($config['version'] == "1.3") {
526
		/* convert shaper rules (make pipes) */
527
		if (is_array($config['pfqueueing']['rule'])) {
528
			$config['pfqueueing']['pipe'] = array();
529

    
530
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
531
				$curent = &$config['pfqueueing']['rule'][$i];
532

    
533
				/* make new pipe and associate with this rule */
534
				$newpipe = array();
535
				$newpipe['descr'] = $curent['descr'];
536
				$newpipe['bandwidth'] = $curent['bandwidth'];
537
				$newpipe['delay'] = $curent['delay'];
538
				$newpipe['mask'] = $curent['mask'];
539
				$config['pfqueueing']['pipe'][$i] = $newpipe;
540

    
541
				$curent['targetpipe'] = $i;
542

    
543
				unset($curent['bandwidth']);
544
				unset($curent['delay']);
545
				unset($curent['mask']);
546
			}
547
		}
548

    
549
		$config['version'] = "1.4";
550
	}
551

    
552
	/* Convert 1.4 -> 1.5 */
553
	if ($config['version'] == "1.4") {
554

    
555
		/* Default route moved */
556
		if (isset($config['interfaces']['wan']['gateway']))
557
			if ($config['interfaces']['wan']['gateway'] <> "")
558
				$config['system']['gateway'] = $config['interfaces']['wan']['gateway'];
559
		unset($config['interfaces']['wan']['gateway']);
560

    
561
                /* Queues are no longer interface specific */
562
                if (isset($config['interfaces']['lan']['schedulertype']))
563
                        unset($config['interfaces']['lan']['schedulertype']);
564
                if (isset($config['interfaces']['wan']['schedulertype']))
565
                        unset($config['interfaces']['wan']['schedulertype']);
566

    
567
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
568
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
569
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
570
                }
571

    
572
		$config['version'] = "1.5";
573
	}
574

    
575
	/* Convert 1.5 -> 1.6 */
576
	if ($config['version'] == "1.5") {
577
		/* Alternate firmware URL moved */
578
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
579
			$config['system']['alt_firmware_url'] = array();
580
			$config['system']['alt_firmware_url']['enabled'] = "";
581
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
582
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
583
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
584
		} else {
585
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
586
		}
587

    
588
		$config['version'] = "1.6";
589
	}
590

    
591
	if ($prev_version != $config['version'])
592
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
593
}
594

    
595
/****f* config/write_config
596
 * NAME
597
 *   write_config - Backup and write the firewall configuration.
598
 * DESCRIPTION
599
 *   write_config() handles backing up the current configuration,
600
 *   applying changes, and regenerating the configuration cache.
601
 * INPUTS
602
 *   $desc	- string containing the a description of configuration changes
603
 *   $backup	- boolean: do not back up current configuration if false.
604
 * RESULT
605
 *   null       
606
 ******/
607
/* save the system configuration */
608
function write_config($desc="Unknown", $backup = true) {
609
	global $config, $g;
610

    
611
	if($backup) backup_config();
612

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

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

    
620
	$config['revision']['description'] = $desc;
621
	$config['revision']['time'] = $changetime;
622
	
623
	config_lock();
624
	conf_mount_rw();
625

    
626
	/* generate configuration XML */
627
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
628

    
629
	/* write new configuration */
630
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
631
	if (!$fd)
632
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
633
	fwrite($fd, $xmlconfig);
634
	fclose($fd);
635

    
636
	conf_mount_ro();
637
	config_unlock();
638

    
639
	// Always reparse the config after it's written - something is getting lost in serialize().
640
	$config = parse_config(true);
641
	return $config;
642
}
643

    
644
/****f* config/reset_factory_defaults
645
 * NAME
646
 *   reset_factory_defaults - Reset the system to its default configuration.
647
 * RESULT
648
 *   integer	- indicates completion
649
 ******/
650
function reset_factory_defaults() {
651
	global $g;
652

    
653
	config_lock();
654
	conf_mount_rw();
655

    
656
	/* create conf directory, if necessary */
657
	safe_mkdir("{$g['cf_conf_path']}");
658

    
659
	/* clear out /conf */
660
	$dh = opendir($g['conf_path']);
661
	while ($filename = readdir($dh)) {
662
		if (($filename != ".") && ($filename != "..")) {
663
			unlink_if_exists($g['conf_path'] . "/" . $filename);
664
		}
665
	}
666
	closedir($dh);
667

    
668
	/* copy default configuration */
669
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
670

    
671
	conf_mount_ro();
672
	config_unlock();
673

    
674
	return 0;
675
}
676

    
677
function config_restore($conffile) {
678
	global $config, $g;
679
       
680
        if (!file_exists($conffile))
681
                return 1;
682
        
683
        config_lock();
684
        conf_mount_rw();        
685
        
686
        backup_config();
687
        copy($conffile, "{$g['cf_conf_path']}/config.xml");
688
	$config = parse_config(true);
689
        write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
690
        
691
        conf_mount_ro();
692
        config_unlock();
693

    
694
        return 0;
695
}
696

    
697

    
698

    
699
function config_install($conffile) {
700
        global $config, $g;
701
        
702
        if (!file_exists($conffile))
703
                return 1;
704

    
705
	if($g['booting'] == true)
706
		echo "Installing configuration...\n";
707
 
708
        config_lock();
709
        conf_mount_rw();
710
        
711
        copy($conffile, "{$g['conf_path']}/config.xml");
712
                
713
        conf_mount_ro();
714
        config_unlock();
715

    
716
        return 0;
717
}
718

    
719
/* lock configuration file, decide that the lock file is stale after
720
   10 seconds */
721
function config_lock() {
722
	global $g, $process_lock;
723

    
724
	/* No need to continue if we're the ones holding the lock */
725
	if ($process_lock)
726
		return;
727

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

    
730
	$n = 0;
731
	while ($n < 10) {
732
		/* open the lock file in append mode to avoid race condition */
733
		if ($fd = @fopen($lockfile, "x")) {
734
			/* succeeded */
735
			$process_lock = true;
736
			fclose($fd);
737
			return;
738
		} else {
739
			/* file locked, wait and try again */
740
			$process_lock = false;
741
			sleep(1);
742
			$n++;
743
		}
744
	}
745
}
746

    
747
/* unlock configuration file */
748
function config_unlock() {
749
	global $g, $process_lock;
750

    
751
	$lockfile = "{$g['varrun_path']}/config.lock";
752
	$process_lock = false;
753

    
754
	unlink_if_exists($lockfile);
755
}
756

    
757
function set_networking_interfaces_ports() {
758
	global $noreboot;
759
	global $config;
760
	global $g;
761
	global $fp;
762

    
763
	$fp = fopen('php://stdin', 'r');
764

    
765
	$iflist = get_interface_list();
766

    
767
	echo <<<EOD
768

    
769
Valid interfaces are:
770

    
771

    
772
EOD;
773

    
774
	foreach ($iflist as $iface => $ifa) {
775
		echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
776
			$ifa['up'] ? "   (up)" : "");
777
	}
778

    
779
	echo <<<EOD
780

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

    
785
Do you want to set up VLANs now [y|n]?
786
EOD;
787

    
788
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
789
		vlan_setup();
790

    
791
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
792

    
793
		echo "\n\nVLAN interfaces:\n\n";
794
		$i = 0;
795
		foreach ($config['vlans']['vlan'] as $vlan) {
796

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

    
800
			$iflist['vlan' . $i] = array();
801
			$i++;
802
		}
803
	}
804

    
805
	echo <<<EOD
806

    
807
If you do not know the names of your interfaces, you may choose to use
808
auto-detection. In that case, disconnect all interfaces before you begin,
809
and reconnect each one when prompted to do so.
810

    
811
EOD;
812

    
813
	do {
814
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
815
		$lanif = chop(fgets($fp));
816
		if ($lanif === "") {
817
			exit(0);
818
		}
819

    
820
		if ($lanif === "a")
821
			$lanif = autodetect_interface("LAN", $fp);
822
		else if (!array_key_exists($lanif, $iflist)) {
823
			echo "\nInvalid interface name '{$lanif}'\n";
824
			unset($lanif);
825
			continue;
826
		}
827
	} while (!$lanif);
828

    
829
	do {
830
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
831
		$wanif = chop(fgets($fp));
832
		if ($wanif === "") {
833
			exit(0);
834
		}
835
		if ($wanif === "a")
836
			$wanif = autodetect_interface("WAN", $fp);
837
		else if (!array_key_exists($wanif, $iflist)) {
838
			echo "\nInvalid interface name '{$wanif}'\n";
839
			unset($wanif);
840
			continue;
841
		}
842
	} while (!$wanif);
843

    
844
	/* optional interfaces */
845
	$i = 0;
846
	$optif = array();
847

    
848
	while (1) {
849
		if ($optif[$i])
850
			$i++;
851
		$i1 = $i + 1;
852
		echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
853
			"(or nothing if finished): ";
854
		$optif[$i] = chop(fgets($fp));
855

    
856
		if ($optif[$i]) {
857
			if ($optif[$i] === "a") {
858
				$ad = autodetect_interface("Optional " . $i1, $fp);
859
				if ($ad)
860
					$optif[$i] = $ad;
861
				else
862
					unset($optif[$i]);
863
			} else if (!array_key_exists($optif[$i], $iflist)) {
864
				echo "\nInvalid interface name '{$optif[$i]}'\n";
865
				unset($optif[$i]);
866
				continue;
867
			}
868
		} else {
869
			unset($optif[$i]);
870
			break;
871
		}
872
	}
873

    
874
	/* check for double assignments */
875
	$ifarr = array_merge(array($lanif, $wanif), $optif);
876

    
877
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
878
		for ($j = ($i+1); $j < count($ifarr); $j++) {
879
			if ($ifarr[$i] == $ifarr[$j]) {
880
				echo <<<EOD
881

    
882
Error: you cannot assign the same interface name twice!
883

    
884
EOD;
885

    
886
				exit(0);
887
			}
888
		}
889
	}
890

    
891
	echo <<<EOD
892

    
893
The interfaces will be assigned as follows:
894

    
895
LAN  -> {$lanif}
896
WAN  -> {$wanif}
897

    
898
EOD;
899

    
900
	for ($i = 0; $i < count($optif); $i++) {
901
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
902
	}
903

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

    
906
echo <<<EOD
907

    
908
Do you want to proceed [y|n]?
909
EOD;
910

    
911
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
912

    
913
		$config['interfaces']['lan']['if'] = $lanif;
914
		if (preg_match($g['wireless_regex'], $lanif)) {
915
			if (!is_array($config['interfaces']['lan']['wireless']))
916
				$config['interfaces']['lan']['wireless'] = array();
917
		} else {
918
			unset($config['interfaces']['lan']['wireless']);
919
		}
920
		
921
		$config['interfaces']['wan']['if'] = $wanif;
922
		if (preg_match($g['wireless_regex'], $wanif)) {
923
			if (!is_array($config['interfaces']['wan']['wireless']))
924
				$config['interfaces']['wan']['wireless'] = array();
925
		} else {
926
			unset($config['interfaces']['wan']['wireless']);
927
		}
928
		
929
		for ($i = 0; $i < count($optif); $i++) {
930
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
931
				$config['interfaces']['opt' . ($i+1)] = array();
932
			
933
			$config['interfaces']['opt' . ($i+1)]['if'] = $optif[$i];
934
			
935
			/* wireless interface? */
936
			if (preg_match($g['wireless_regex'], $optif[$i])) {
937
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
938
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
939
			} else {
940
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
941
			}
942
			
943
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
944
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
945
		}
946
		
947
		/* remove all other (old) optional interfaces */
948
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
949
			unset($config['interfaces']['opt' . ($i+1)]);
950
		
951
		write_config();
952
		
953
		echo <<<EOD
954

    
955

    
956

    
957
EOD;
958

    
959
		if($noreboot <> true)
960
			system_reboot_sync();
961
	}
962
}
963

    
964
function autodetect_interface($ifname, $fp) {
965
	$iflist_prev = get_interface_list();
966
	echo <<<EOD
967

    
968
Connect the {$ifname} interface now and make sure that the link is up.
969
Then press ENTER to continue.
970

    
971
EOD;
972
	fgets($fp);
973
	$iflist = get_interface_list();
974

    
975
	foreach ($iflist_prev as $ifn => $ifa) {
976
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
977
			echo "Detected link-up on interface {$ifn}.\n";
978
			return $ifn;
979
		}
980
	}
981

    
982
	echo "No link-up detected.\n";
983

    
984
	return null;
985
}
986

    
987
function vlan_setup() {
988
	global $iflist, $config, $g, $fp;
989

    
990
	$iflist = get_interface_list();
991

    
992
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
993

    
994
	echo <<<EOD
995

    
996
WARNING: all existing VLANs will be cleared if you proceed!
997

    
998
Do you want to proceed [y|n]?
999
EOD;
1000

    
1001
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1002
		return;
1003
	}
1004

    
1005
	$config['vlans']['vlan'] = array();
1006
	echo "\n";
1007

    
1008
	while (1) {
1009
		$vlan = array();
1010

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

    
1014
		if ($vlan['if']) {
1015
			if (!array_key_exists($vlan['if'], $iflist)) {
1016
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1017
				continue;
1018
			}
1019
		} else {
1020
			break;
1021
		}
1022

    
1023
		echo "Enter the VLAN tag (1-4094): ";
1024
		$vlan['tag'] = chop(fgets($fp));
1025

    
1026
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1027
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1028
			continue;
1029
		}
1030

    
1031
		$config['vlans']['vlan'][] = $vlan;
1032
	}
1033
}
1034

    
1035
function system_start_ftp_helpers() {
1036
	require_once("interfaces.inc");
1037
	global $config, $g;
1038
	if($config['system']['disableftpproxy'] <> "") 
1039
		return;
1040
	$wanip = get_current_wan_address();
1041
	mwexec("/usr/bin/killall pftpx");
1042
	if($wanip <> "" and $wanip <> "0.0.0.0") 
1043
		$pip = "-p {$wanip}";
1044
	mwexec("/usr/local/sbin/pftpx -g 8021 {$wanip}");
1045
}
1046

    
1047
function cleanup_backupcache($revisions = 30) {
1048
	global $g;
1049
	$i = false;
1050
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1051
		$backups = get_backups();
1052
		$newbaks = array();
1053
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1054
		$baktimes = $backups['versions'];
1055
		$tocache = array();
1056
		unset($backups['versions']);
1057
       		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1058
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));	
1059
                	if(!in_array($tocheck, $baktimes)) {
1060
				$i = true;
1061
				if($bootup) print " " . $tocheck . "a";
1062
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1063
				if($newxml['revision']['description'] == "") $newxml['revision']['description'] = "Unknown";
1064
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1065
			}
1066
        	}
1067
		foreach($backups as $checkbak) {
1068
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1069
				$newbaks[] = $checkbak;
1070
			} else {
1071
				$i = true;
1072
				if($bootup) print " " . $tocheck . "r";
1073
			}
1074
		}
1075
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);	
1076
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1077
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1078
			foreach($toslice as $sliced) $newcache[$sliced] = $tocache[$sliced];
1079
			foreach($tocache as $version => $versioninfo) {
1080
				if(!in_array($version, array_keys($newcache))) {
1081
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1082
					if($bootup) print " " . $tocheck . "d";
1083
				}
1084
			}
1085
			$tocache = $newcache;
1086
		}
1087
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1088
        	fwrite($bakout, serialize($tocache));
1089
  	        fclose($bakout);
1090
	}
1091
	if($g['booting']) {
1092
		if($i) {
1093
			print "done.\n";
1094
		}
1095
	}
1096
}
1097
  	 
1098
function get_backups() { 	 
1099
	global $g;
1100

    
1101
        if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1102
                $confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1103
		$bakvers = array_keys($confvers);
1104
		$toreturn = array();
1105
		sort($bakvers);
1106
		// $bakvers = array_reverse($bakvers);
1107
		foreach(array_reverse($bakvers) as $bakver) $toreturn[] = array('time' => $bakver,
1108
								 'description' => $confvers[$bakver]['description']
1109
								);
1110
        } else { 	 
1111
                return false; 	 
1112
        }
1113
	$toreturn['versions'] = $bakvers;
1114
        return $toreturn;
1115
}
1116

    
1117
function backup_config() {
1118
	global $config, $g;
1119

    
1120
	/* XXX: temporary */
1121
	if($g['platform'] == "cdrom")
1122
		return;
1123

    
1124
	conf_mount_rw();
1125

    
1126
	/* Create backup directory if needed */
1127
	safe_mkdir("{$g['cf_conf_path']}/backup");
1128

    
1129
        if($config['revision']['time'] == "") {
1130
                $baktime = 0;
1131
        } else {
1132
                $baktime = $config['revision']['time'];
1133
        }
1134
        if($config['revision']['description'] == "") {
1135
                $bakdesc = "Unknown";
1136
        } else {
1137
                $bakdesc = $config['revision']['description'];
1138
        }
1139
        copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1140
        if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1141
                $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1142
        } else {
1143
                $backupcache = array();
1144
        }
1145
        $backupcache[$baktime] = array('description' => $bakdesc);
1146
        $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1147
        fwrite($bakout, serialize($backupcache));
1148
        fclose($bakout);
1149
	
1150
	conf_mount_ro();
1151
	
1152
	return true;
1153
}
1154

    
1155
function mute_kernel_msgs() {
1156
	exec("/sbin/conscontrol mute on");
1157
}
1158

    
1159
function unmute_kernel_msgs() {
1160
	exec("/sbin/conscontrol mute off");
1161
}
1162

    
1163
?>
(3-3/20)