Project

General

Profile

Download (29.7 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
/* include globals/utility/XML parser files */
42
require_once("globals.inc");
43
require_once("util.inc");
44
require_once("pfsense-utils.inc");
45
require_once("xmlparse.inc");
46

    
47
/* read platform */
48
if (file_exists("{$g['etc_path']}/platform")) {
49
	$g['platform'] = chop(file_get_contents("{$g['etc_path']}/platform"));
50
} else {
51
	$g['platform'] = "unknown";
52
}
53

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

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

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

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

    
92
					if ($cfgdevice)
93
						break;
94
				}
95
				if (mwexec("/sbin/mount -r /dev/{$mountdisk}d {$g['cf_path']}") == 0) {
96
					if (file_exists("{$g['cf_conf_path']}/config.xml")) {
97
						/* found it */
98
						$cfgdevice = $mountdisk;
99
						$cfgpartition = $cfgdevice . "d";
100
						$cfgfstype = "ufs";
101
						echo "Found configuration on $cfgdevice.\n";
102
					}
103

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

    
106
					if ($cfgdevice)
107
						break;
108
				}
109
			}
110
		}
111

    
112
		if (!$cfgdevice) {
113
			/* no device found, print an error and die */
114
			echo <<<EOD
115

    
116

    
117
*******************************************************************************
118
* FATAL ERROR                                                                 *
119
* The device that contains the configuration file (config.xml) could not be   *
120
* found. pfSense cannot continue booting.                                     *
121
*******************************************************************************
122

    
123

    
124
EOD;
125

    
126
			mwexec("/sbin/halt");
127
			exit;
128
		}
129

    
130
		/* write device name to a file for rc.firmware */
131
		$fd = fopen("{$g['varetc_path']}/cfdevice", "w");
132
		fwrite($fd, $cfgdevice . "\n");
133
		fclose($fd);
134

    
135
		/* write out an fstab */
136
		$fd = fopen("{$g['etc_path']}/fstab", "w");
137

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

    
141
		fwrite($fd, $fstab);
142
		fclose($fd);
143
	}
144

    
145
	/* mount all filesystems */
146
	mwexec("/sbin/mount -a");
147
}
148

    
149
/* This global seems to be finicky. Default to always parsing.
150
if(!$g['booting']) {
151
	$config = parse_config();
152
}
153
*/
154

    
155
$config = parse_config();
156

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

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

    
188
function generate_config_cache($config) {
189
	global $g;
190
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
191
	fwrite($configcache, serialize($config));
192
	fclose($configcache);
193
	return true;
194
}
195

    
196
function parse_config_bootup() {
197
	global $config, $g;
198
	if (!$noparseconfig) {
199
		if (!file_exists("{$g['conf_path']}/config.xml")) {
200
			config_lock();
201
			if ($g['booting']) {
202
				if (strstr($g['platform'], "cdrom")) {
203
					/* try copying the default config. to the floppy */
204
					reset_factory_defaults();
205
	
206
					echo "No XML configuration file found - using factory defaults.\n";
207
					echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
208
					echo "file is inserted. If it isn't, your configuration changes will be lost\n";
209
					echo "on reboot.\n";
210
				} else {
211
					echo "XML configuration file not found.  pfSense cannot continue booting.\n";
212
					mwexec("/sbin/halt");
213
					exit;
214
				}
215
			} else {
216
				config_unlock();
217
				exit(0);
218
			}
219
		}
220
	}
221

    
222
	parse_config(true);
223
	
224
	if ((float)$config['version'] > (float)$g['latest_config']) {
225
		echo <<<EOD
226

    
227

    
228
*******************************************************************************
229
* WARNING!                                                                    *
230
* The current configuration has been created with a newer version of pfSense  *
231
* than this one! This can lead to serious misbehavior and even security       *
232
* holes! You are urged to either upgrade to a newer version of pfSense or     *
233
* revert to the default configuration immediately!                            *
234
*******************************************************************************
235

    
236

    
237
EOD;
238
		}
239

    
240
	/* make alias table (for faster lookups) */
241
	alias_make_table();
242
	config_unlock();
243
}
244

    
245
/* mount flash card read/write */
246
function conf_mount_rw() {
247
	global $g;
248

    
249
	/* don't use mount -u anymore
250
	   (doesn't sync the files properly and /bin/sync won't help either) */
251
	mwexec("/sbin/umount -f {$g['cf_path']}");
252
	$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
253
	while($status == -1) {
254
		mwexec("fsck -y");
255
		$status = mwexec("/sbin/mount -w -o noatime {$g['cf_path']}");
256
	}
257
	/* if the platform is soekris or wrap, lets mount the
258
	   compact flash card. */
259
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx") {
260
		mwexec("/sbin/umount -f {$g['embeddedbootupslice']}");
261
		mwexec("/sbin/mount -w {$g['embeddedbootupslice']}");
262
	}
263
}
264

    
265
/* mount flash card read only */
266
function conf_mount_ro() {
267
	global $g;
268

    
269
	mwexec("/sbin/umount -f {$g['cf_path']}");
270
	mwexec("/sbin/mount -r {$g['cf_path']}");
271
	/* if the platform is soekris or wrap, lets unmount the
272
	   compact flash card. */
273
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx") {
274
		mwexec("/sbin/umount -f {$g['embeddedbootupslice']}");
275
		mwexec("/sbin/mount -r {$g['embeddedbootupslice']}");
276
	}
277
}
278

    
279
/* convert configuration, if necessary */
280
function convert_config() {
281
	global $config, $pkg_config, $g;
282

    
283
	if ($config['version'] == $g['latest_config'])
284
		return;		/* already at latest version */
285

    
286
	// Save off config version
287
	$prev_version = $config['version'];
288

    
289
	/* convert 1.0 -> 1.1 */
290
	if ($config['version'] == "1.0") {
291
		$opti = 1;
292
		$ifmap = array('lan' => 'lan', 'wan' => 'wan', 'pptp' => 'pptp');
293

    
294
		/* convert DMZ to optional, if necessary */
295
		if (isset($config['interfaces']['dmz'])) {
296

    
297
			$dmzcfg = &$config['interfaces']['dmz'];
298

    
299
			if ($dmzcfg['if']) {
300
				$config['interfaces']['opt' . $opti] = array();
301
				$optcfg = &$config['interfaces']['opt' . $opti];
302

    
303
				$optcfg['enable'] = $dmzcfg['enable'];
304
				$optcfg['descr'] = "DMZ";
305
				$optcfg['if'] = $dmzcfg['if'];
306
				$optcfg['ipaddr'] = $dmzcfg['ipaddr'];
307
				$optcfg['subnet'] = $dmzcfg['subnet'];
308

    
309
				$ifmap['dmz'] = "opt" . $opti;
310
				$opti++;
311
			}
312

    
313
			unset($config['interfaces']['dmz']);
314
		}
315

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

    
319
			if (!$config['interfaces']['wlan' . $i]['if']) {
320
				unset($config['interfaces']['wlan' . $i]);
321
				continue;
322
			}
323

    
324
			$wlancfg = &$config['interfaces']['wlan' . $i];
325
			$config['interfaces']['opt' . $opti] = array();
326
			$optcfg = &$config['interfaces']['opt' . $opti];
327

    
328
			$optcfg['enable'] = $wlancfg['enable'];
329
			$optcfg['descr'] = "WLAN" . $i;
330
			$optcfg['if'] = $wlancfg['if'];
331
			$optcfg['ipaddr'] = $wlancfg['ipaddr'];
332
			$optcfg['subnet'] = $wlancfg['subnet'];
333
			$optcfg['bridge'] = $wlancfg['bridge'];
334

    
335
			$optcfg['wireless'] = array();
336
			$optcfg['wireless']['mode'] = $wlancfg['mode'];
337
			$optcfg['wireless']['ssid'] = $wlancfg['ssid'];
338
			$optcfg['wireless']['channel'] = $wlancfg['channel'];
339
			$optcfg['wireless']['wep'] = $wlancfg['wep'];
340

    
341
			$ifmap['wlan' . $i] = "opt" . $opti;
342

    
343
			unset($config['interfaces']['wlan' . $i]);
344
			$opti++;
345
		}
346

    
347
		/* convert filter rules */
348
		$n = count($config['filter']['rule']);
349
		for ($i = 0; $i < $n; $i++) {
350

    
351
			$fr = &$config['filter']['rule'][$i];
352

    
353
			/* remap interface */
354
			if (array_key_exists($fr['interface'], $ifmap))
355
				$fr['interface'] = $ifmap[$fr['interface']];
356
			else {
357
				/* remove the rule */
358
				echo "\nWarning: filter rule removed " .
359
					"(interface '{$fr['interface']}' does not exist anymore).";
360
				unset($config['filter']['rule'][$i]);
361
				continue;
362
			}
363

    
364
			/* remap source network */
365
			if (isset($fr['source']['network'])) {
366
				if (array_key_exists($fr['source']['network'], $ifmap))
367
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
368
				else {
369
					/* remove the rule */
370
					echo "\nWarning: filter rule removed " .
371
						"(source network '{$fr['source']['network']}' does not exist anymore).";
372
					unset($config['filter']['rule'][$i]);
373
					continue;
374
				}
375
			}
376

    
377
			/* remap destination network */
378
			if (isset($fr['destination']['network'])) {
379
				if (array_key_exists($fr['destination']['network'], $ifmap))
380
					$fr['destination']['network'] = $ifmap[$fr['destination']['network']];
381
				else {
382
					/* remove the rule */
383
					echo "\nWarning: filter rule removed " .
384
						"(destination network '{$fr['destination']['network']}' does not exist anymore).";
385
					unset($config['filter']['rule'][$i]);
386
					continue;
387
				}
388
			}
389
		}
390

    
391
		/* convert shaper rules */
392
		$n = count($config['pfqueueing']['rule']);
393
		if (is_array($config['pfqueueing']['rule']))
394
			for ($i = 0; $i < $n; $i++) {
395

    
396
			$fr = &$config['pfqueueing']['rule'][$i];
397

    
398
			/* remap interface */
399
			if (array_key_exists($fr['interface'], $ifmap))
400
				$fr['interface'] = $ifmap[$fr['interface']];
401
			else {
402
				/* remove the rule */
403
				echo "\nWarning: traffic shaper rule removed " .
404
					"(interface '{$fr['interface']}' does not exist anymore).";
405
				unset($config['pfqueueing']['rule'][$i]);
406
				continue;
407
			}
408

    
409
			/* remap source network */
410
			if (isset($fr['source']['network'])) {
411
				if (array_key_exists($fr['source']['network'], $ifmap))
412
					$fr['source']['network'] = $ifmap[$fr['source']['network']];
413
				else {
414
					/* remove the rule */
415
					echo "\nWarning: traffic shaper rule removed " .
416
						"(source network '{$fr['source']['network']}' does not exist anymore).";
417
					unset($config['pfqueueing']['rule'][$i]);
418
					continue;
419
				}
420
			}
421

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

    
436
		$config['version'] = "1.1";
437
	}
438

    
439
	/* convert 1.1 -> 1.2 */
440
	if ($config['version'] == "1.1") {
441
		/* move LAN DHCP server config */
442
		$tmp = $config['dhcpd'];
443
		$config['dhcpd'] = array();
444
		$config['dhcpd']['lan'] = $tmp;
445

    
446
		/* encrypt password */
447
		$config['system']['password'] = crypt($config['system']['password']);
448

    
449
		$config['version'] = "1.2";
450
	}
451

    
452
	/* convert 1.2 -> 1.3 */
453
	if ($config['version'] == "1.2") {
454
		/* convert advanced outbound NAT config */
455
		for ($i = 0; isset($config['nat']['advancedoutbound']['rule'][$i]); $i++) {
456
			$curent = &$config['nat']['advancedoutbound']['rule'][$i];
457
			$src = $curent['source'];
458
			$curent['source'] = array();
459
			$curent['source']['network'] = $src;
460
			$curent['destination'] = array();
461
			$curent['destination']['any'] = true;
462
		}
463

    
464
		/* add an explicit type="pass" to all filter rules to make things consistent */
465
		for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
466
			$config['filter']['rule'][$i]['type'] = "pass";
467
		}
468

    
469
		$config['version'] = "1.3";
470
	}
471

    
472
	/* convert 1.3 -> 1.4 */
473
	if ($config['version'] == "1.3") {
474
		/* convert shaper rules (make pipes) */
475
		if (is_array($config['pfqueueing']['rule'])) {
476
			$config['pfqueueing']['pipe'] = array();
477

    
478
			for ($i = 0; isset($config['pfqueueing']['rule'][$i]); $i++) {
479
				$curent = &$config['pfqueueing']['rule'][$i];
480

    
481
				/* make new pipe and associate with this rule */
482
				$newpipe = array();
483
				$newpipe['descr'] = $curent['descr'];
484
				$newpipe['bandwidth'] = $curent['bandwidth'];
485
				$newpipe['delay'] = $curent['delay'];
486
				$newpipe['mask'] = $curent['mask'];
487
				$config['pfqueueing']['pipe'][$i] = $newpipe;
488

    
489
				$curent['targetpipe'] = $i;
490

    
491
				unset($curent['bandwidth']);
492
				unset($curent['delay']);
493
				unset($curent['mask']);
494
			}
495
		}
496

    
497
		$config['version'] = "1.4";
498
	}
499

    
500
	/* Convert 1.4 -> 1.5 */
501
	if ($config['version'] == "1.4") {
502

    
503
		/* Default route moved */
504
		if (isset($config['interfaces']['wan']['gateway']))
505
			if ($config['interfaces']['wan']['gateway'] <> "")
506
				$config['system']['gateway'] = $config['interfaces']['wan']['gateway'];
507
		unset($config['interfaces']['wan']['gateway']);
508

    
509
                /* Queues are no longer interface specific */
510
                if (isset($config['interfaces']['lan']['schedulertype']))
511
                        unset($config['interfaces']['lan']['schedulertype']);
512
                if (isset($config['interfaces']['wan']['schedulertype']))
513
                        unset($config['interfaces']['wan']['schedulertype']);
514

    
515
                for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) {
516
                        if(isset($config['interfaces']['opt' . $i]['schedulertype']))
517
                                unset($config['interfaces']['opt' . $i]['schedulertype']);
518
                }
519

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

    
523
	/* Convert 1.5 -> 1.6 */
524
	if ($config['version'] == "1.5") {
525
		/* Alternate firmware URL moved */
526
		if (isset($config['system']['firmwareurl']) && isset($config['system']['firmwarename'])) { // Only convert if *both* are defined.
527
			$config['system']['alt_firmware_url'] = array();
528
			$config['system']['alt_firmware_url']['enabled'] = "";
529
			$config['system']['alt_firmware_url']['firmware_base_url'] = $config['system']['firmwareurl'];
530
			$config['system']['alt_firmware_url']['firmware_filename'] = $config['system']['firmwarename'];
531
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
532
		} else {
533
			unset($config['system']['firmwareurl'], $config['system']['firmwarename']);
534
		}
535

    
536
		$config['version'] = "1.6";
537
	}
538

    
539
	if ($prev_version != $config['version'])
540
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
541
}
542

    
543
/* save the system configuration */
544
function write_config($desc="Unknown", $backup = true) {
545
	global $config, $g;
546

    
547
	if($backup) backup_config();
548

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

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

    
556
	$config['revision']['description'] = $desc;
557
	$config['revision']['time'] = $changetime;
558
	
559
	config_lock();
560
	conf_mount_rw();
561

    
562
	/* generate configuration XML */
563
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
564

    
565
	/* write new configuration */
566
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
567
	if (!$fd)
568
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
569
	fwrite($fd, $xmlconfig);
570
	fclose($fd);
571

    
572
	conf_mount_ro();
573
	config_unlock();
574

    
575
	generate_config_cache($config);
576
	cleanup_backupcache();
577
	return $config;
578
}
579

    
580
function reset_factory_defaults() {
581
	global $g;
582

    
583
	config_lock();
584
	conf_mount_rw();
585

    
586
	/* create conf directory, if necessary */
587
	safe_mkdir("{$g['cf_conf_path']}");
588

    
589
	/* clear out /conf */
590
	$dh = opendir($g['conf_path']);
591
	while ($filename = readdir($dh)) {
592
		if (($filename != ".") && ($filename != "..")) {
593
			unlink_if_exists($g['conf_path'] . "/" . $filename);
594
		}
595
	}
596
	closedir($dh);
597

    
598
	/* copy default configuration */
599
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
600

    
601
	conf_mount_ro();
602
	config_unlock();
603

    
604
	return 0;
605
}
606

    
607
function config_restore($conffile) {
608
	global $config, $g;
609
       
610
        if (!file_exists($conffile))
611
                return 1;
612
        
613
        config_lock();
614
        conf_mount_rw();        
615
        
616
        backup_config();
617
        copy($conffile, "{$g['cf_conf_path']}/config.xml");
618
	$config = parse_config(true);
619
        write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
620
        
621
        conf_mount_ro();
622
        config_unlock();
623

    
624
        return 0;
625
}
626

    
627

    
628

    
629
function config_install($conffile) {
630
        global $config, $g;
631
        
632
        if (!file_exists($conffile))
633
                return 1;
634
 
635
        config_lock();
636
        conf_mount_rw();
637
        
638
        copy($conffile, "{$g['conf_path']}/config.xml");
639
                
640
        conf_mount_ro();
641
        config_unlock();
642

    
643
        return 0;
644
}
645

    
646
/* lock configuration file, decide that the lock file is stale after
647
   10 seconds */
648
function config_lock() {
649
	global $g, $process_lock;
650

    
651
	/* No need to continue if we're the ones holding the lock */
652
	if ($process_lock)
653
		return;
654

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

    
657
	$n = 0;
658
	while ($n < 10) {
659
		/* open the lock file in append mode to avoid race condition */
660
		if ($fd = @fopen($lockfile, "x")) {
661
			/* succeeded */
662
			$process_lock = true;
663
			fclose($fd);
664
			return;
665
		} else {
666
			/* file locked, wait and try again */
667
			$process_lock = false;
668
			sleep(1);
669
			$n++;
670
		}
671
	}
672
}
673

    
674
/* unlock configuration file */
675
function config_unlock() {
676
	global $g, $process_lock;
677

    
678
	$lockfile = "{$g['varrun_path']}/config.lock";
679
	$process_lock = false;
680

    
681
	unlink_if_exists($lockfile);
682
}
683

    
684
function set_networking_interfaces_ports() {
685
	global $noreboot;
686
	global $config;
687
	global $g;
688
	global $fp;
689

    
690
	$fp = fopen('php://stdin', 'r');
691

    
692
	$iflist = get_interface_list();
693

    
694
	echo <<<EOD
695

    
696
Valid interfaces are:
697

    
698

    
699
EOD;
700

    
701
	foreach ($iflist as $iface => $ifa) {
702
		echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
703
			$ifa['up'] ? "   (up)" : "");
704
	}
705

    
706
	echo <<<EOD
707

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

    
712
Do you want to set up VLANs now [y|n]?
713
EOD;
714

    
715
	if (strcasecmp(chop(fgets($fp)), "y") == 0)
716
		vlan_setup();
717

    
718
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
719

    
720
		echo "\n\nVLAN interfaces:\n\n";
721
		$i = 0;
722
		foreach ($config['vlans']['vlan'] as $vlan) {
723

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

    
727
			$iflist['vlan' . $i] = array();
728
			$i++;
729
		}
730
	}
731

    
732
	echo <<<EOD
733

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

    
738
EOD;
739

    
740
	do {
741
		echo "\nEnter the LAN interface name or 'a' for auto-detection: ";
742
		$lanif = chop(fgets($fp));
743
		if ($lanif === "") {
744
			exit(0);
745
		}
746

    
747
		if ($lanif === "a")
748
			$lanif = autodetect_interface("LAN", $fp);
749
		else if (!array_key_exists($lanif, $iflist)) {
750
			echo "\nInvalid interface name '{$lanif}'\n";
751
			unset($lanif);
752
			continue;
753
		}
754
	} while (!$lanif);
755

    
756
	do {
757
		echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
758
		$wanif = chop(fgets($fp));
759
		if ($wanif === "") {
760
			exit(0);
761
		}
762
		if ($wanif === "a")
763
			$wanif = autodetect_interface("WAN", $fp);
764
		else if (!array_key_exists($wanif, $iflist)) {
765
			echo "\nInvalid interface name '{$wanif}'\n";
766
			unset($wanif);
767
			continue;
768
		}
769
	} while (!$wanif);
770

    
771
	/* optional interfaces */
772
	$i = 0;
773
	$optif = array();
774

    
775
	while (1) {
776
		if ($optif[$i])
777
			$i++;
778
		$i1 = $i + 1;
779
		echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
780
			"(or nothing if finished): ";
781
		$optif[$i] = chop(fgets($fp));
782

    
783
		if ($optif[$i]) {
784
			if ($optif[$i] === "a") {
785
				$ad = autodetect_interface("Optional " . $i1, $fp);
786
				if ($ad)
787
					$optif[$i] = $ad;
788
				else
789
					unset($optif[$i]);
790
			} else if (!array_key_exists($optif[$i], $iflist)) {
791
				echo "\nInvalid interface name '{$optif[$i]}'\n";
792
				unset($optif[$i]);
793
				continue;
794
			}
795
		} else {
796
			unset($optif[$i]);
797
			break;
798
		}
799
	}
800

    
801
	/* check for double assignments */
802
	$ifarr = array_merge(array($lanif, $wanif), $optif);
803

    
804
	for ($i = 0; $i < (count($ifarr)-1); $i++) {
805
		for ($j = ($i+1); $j < count($ifarr); $j++) {
806
			if ($ifarr[$i] == $ifarr[$j]) {
807
				echo <<<EOD
808

    
809
Error: you cannot assign the same interface name twice!
810

    
811
EOD;
812

    
813
				exit(0);
814
			}
815
		}
816
	}
817

    
818
	echo <<<EOD
819

    
820
The interfaces will be assigned as follows:
821

    
822
LAN  -> {$lanif}
823
WAN  -> {$wanif}
824

    
825
EOD;
826

    
827
	for ($i = 0; $i < count($optif); $i++) {
828
		echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
829
	}
830

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

    
833
echo <<<EOD
834

    
835
Do you want to proceed [y|n]?
836
EOD;
837

    
838
	if (strcasecmp(chop(fgets($fp)), "y") == 0) {
839

    
840
		$config['interfaces']['lan']['if'] = $lanif;
841
		if (preg_match($g['wireless_regex'], $lanif)) {
842
			if (!is_array($config['interfaces']['lan']['wireless']))
843
				$config['interfaces']['lan']['wireless'] = array();
844
		} else {
845
			unset($config['interfaces']['lan']['wireless']);
846
		}
847
		
848
		$config['interfaces']['wan']['if'] = $wanif;
849
		if (preg_match($g['wireless_regex'], $wanif)) {
850
			if (!is_array($config['interfaces']['wan']['wireless']))
851
				$config['interfaces']['wan']['wireless'] = array();
852
		} else {
853
			unset($config['interfaces']['wan']['wireless']);
854
		}
855
		
856
		for ($i = 0; $i < count($optif); $i++) {
857
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
858
				$config['interfaces']['opt' . ($i+1)] = array();
859
			
860
			$config['interfaces']['opt' . ($i+1)]['if'] = $optif[$i];
861
			
862
			/* wireless interface? */
863
			if (preg_match($g['wireless_regex'], $optif[$i])) {
864
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
865
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
866
			} else {
867
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
868
			}
869
			
870
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
871
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
872
		}
873
		
874
		/* remove all other (old) optional interfaces */
875
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
876
			unset($config['interfaces']['opt' . ($i+1)]);
877
		
878
		write_config();
879
		
880
		echo <<<EOD
881

    
882

    
883

    
884
EOD;
885

    
886
		if($noreboot <> true)
887
			system_reboot_sync();
888
	}
889
}
890

    
891
function autodetect_interface($ifname, $fp) {
892
	$iflist_prev = get_interface_list();
893
	echo <<<EOD
894

    
895
Connect the {$ifname} interface now and make sure that the link is up.
896
Then press ENTER to continue.
897

    
898
EOD;
899
	fgets($fp);
900
	$iflist = get_interface_list();
901

    
902
	foreach ($iflist_prev as $ifn => $ifa) {
903
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
904
			echo "Detected link-up on interface {$ifn}.\n";
905
			return $ifn;
906
		}
907
	}
908

    
909
	echo "No link-up detected.\n";
910

    
911
	return null;
912
}
913

    
914
function vlan_setup() {
915
	global $iflist, $config, $g, $fp;
916

    
917
	$iflist = get_interface_list();
918

    
919
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
920

    
921
	echo <<<EOD
922

    
923
WARNING: all existing VLANs will be cleared if you proceed!
924

    
925
Do you want to proceed [y|n]?
926
EOD;
927

    
928
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
929
		return;
930
	}
931

    
932
	$config['vlans']['vlan'] = array();
933
	echo "\n";
934

    
935
	while (1) {
936
		$vlan = array();
937

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

    
941
		if ($vlan['if']) {
942
			if (!array_key_exists($vlan['if'], $iflist)) {
943
				echo "\nInvalid interface name '{$vlan['if']}'\n";
944
				continue;
945
			}
946
		} else {
947
			break;
948
		}
949

    
950
		echo "Enter the VLAN tag (1-4094): ";
951
		$vlan['tag'] = chop(fgets($fp));
952

    
953
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
954
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
955
			continue;
956
		}
957

    
958
		$config['vlans']['vlan'][] = $vlan;
959
	}
960
}
961

    
962
function system_start_ftp_helpers() {
963
	global $config, $g;
964
	if($config['system']['disableftpproxy'] <> "") return;
965
	$wanif = get_real_wan_interface();
966
	mwexec("/usr/sbin/inetd -wW -C 60");
967
	mwexec("/usr/bin/killall ftpsesame 2>/dev/null");
968
	mwexec("/usr/local/sbin/ftpsesame -i {$wanif} -q ftpproxy");
969
}
970

    
971
function cleanup_backupcache($revisions = "all") {
972
	global $g;
973
	$i = false;
974
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
975
		$backups = get_backups();
976
		$newbaks = array();
977
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
978
		$baktimes = $backups['versions'];
979
		$tocache = array();
980
		unset($backups['versions']);
981
       		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
982
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));	
983
                	if(!in_array($tocheck, $baktimes)) {
984
				$i = true;
985
				if($bootup) print " " . $tocheck . "a";
986
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
987
				if($newxml['revision']['description'] == "") $newxml['revision']['description'] = "Unknown";
988
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
989
			}
990
        	}
991
		foreach($backups as $checkbak) {
992
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
993
				$newbaks[] = $checkbak;
994
			} else {
995
				$i = true;
996
				if($bootup) print " " . $tocheck . "r";
997
			}
998
		}
999
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);	
1000
		if(is_integer($revisions)) {
1001
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1002
			foreach($toslice as $sliced) $newcache[$sliced] = $tocache[$sliced];
1003
			foreach($tocache as $version => $versioninfo) {
1004
				if(!in_array($version, array_keys($newcache))) {
1005
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1006
					if($bootup) print " " . $tocheck . "d";
1007
				}
1008
			}
1009
			$tocache = $newcache;
1010
		}
1011
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1012
        	fwrite($bakout, serialize($tocache));
1013
  	        fclose($bakout);
1014
	}
1015
	if($g['booting']) {
1016
		if($i) {
1017
			print ".\n";
1018
		} else {
1019
			print " done.\n";
1020
		}
1021
	}
1022
}
1023
  	 
1024
function get_backups() { 	 
1025
	global $g;
1026

    
1027
        if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1028
                $confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1029
		$bakvers = array_keys($confvers);
1030
		$toreturn = array();
1031
		sort($bakvers);
1032
		// $bakvers = array_reverse($bakvers);
1033
		foreach(array_reverse($bakvers) as $bakver) $toreturn[] = array('time' => $bakver,
1034
								 'description' => $confvers[$bakver]['description']
1035
								);
1036
        } else { 	 
1037
                return false; 	 
1038
        }
1039
	$toreturn['versions'] = $bakvers;
1040
        return $toreturn;
1041
}
1042

    
1043
function backup_config() {
1044
	global $config, $g;
1045

    
1046
	conf_mount_rw();
1047

    
1048
	/* Create backup directory if needed */
1049
	safe_mkdir("{$g['cf_conf_path']}/backup");
1050

    
1051
        if($config['revision']['time'] == "") {
1052
                $baktime = 0;
1053
        } else {
1054
                $baktime = $config['revision']['time'];
1055
        }
1056
        if($config['revision']['description'] == "") {
1057
                $bakdesc = "Unknown";
1058
        } else {
1059
                $bakdesc = $config['revision']['description'];
1060
        }
1061
        copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1062
        if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1063
                $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1064
        } else {
1065
                $backupcache = array();
1066
        }
1067
        $backupcache[$baktime] = array('description' => $bakdesc);
1068
        $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1069
        fwrite($bakout, serialize($backupcache));
1070
        fclose($bakout);
1071
	
1072
	conf_mount_ro();
1073
	
1074
	return true;
1075
}
1076
?>
(3-3/18)