Project

General

Profile

Download (34.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.lib.inc
12
	Ported from config.inc by Erik Kristensen
13
	Copyright (C) 2004-2006 Scott Ullrich
14
	All rights reserved.
15

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

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

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

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

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

    
41

    
42
	pfSense_BUILDER_BINARIES:	/sbin/mount	/sbin/sysctl	/sbin/umount	/sbin/halt	/sbin/fsck	/bin/sync
43
	pfSense_MODULE:	config
44
*/
45

    
46

    
47
/****f* config/encrypted_configxml
48
 * NAME
49
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
50
 * INPUTS
51
 *   None
52
 * RESULT
53
 *   $config 	- rewrites config.xml without encryption
54
 ******/
55
function encrypted_configxml() {
56
	global $g, $config;
57
	if(file_exists($g['conf_path'] . "/config.xml")) {
58
		if($g['booting']) {
59
			$configtxt = file_get_contents($g['conf_path'] . "/config.xml");			
60
			if(tagfile_deformat($configtxt, $configtxt, "config.xml")) {
61
				$fp = fopen('php://stdin', 'r');
62
				$data = "";
63
				echo "\n\n*** Encrypted config.xml detected ***\n";
64
				while($data == "") {
65
					echo "\nEnter the password to decrypt config.xml: ";
66
					$decrypt_password = chop(fgets($fp));
67
					$data = decrypt_data($configtxt, $decrypt_password);
68
					if(!strstr($data, "<pfsense>"))
69
						$data = "";
70
					if($data) {
71
						$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
72
						fwrite($fd, $data);
73
						fclose($fd);
74
						exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
75
						echo "\nConfig.xml unlocked.\n";
76
						fclose($fp);
77
					} else {
78
						echo "\nInvalid password entered.  Please try again.\n";
79
					}
80
				}
81
			}
82
		}
83
	}
84
}
85

    
86
/****f* config/parse_config
87
 * NAME
88
 *   parse_config - Read in config.cache or config.xml if needed and return $config array
89
 * INPUTS
90
 *   $parse       - boolean to force parse_config() to read config.xml and generate config.cache
91
 * RESULT
92
 *   $config      - array containing all configuration variables
93
 ******/
94
function parse_config($parse = false) {
95
	global $g, $config_parsed;
96
	
97
	$lockkey = lock('config');
98
	$config_parsed = false;
99
	if (!file_exists("{$g['conf_path']}/config.xml") || filesize("{$g['conf_path']}/config.xml") == 0) {
100
		$last_backup = discover_last_backup();
101
		if($last_backup) {
102
			log_error("No config.xml found, attempting last known config restore.");
103
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
104
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
105
		} else {
106
			unlock($lockkey);
107
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
108
		}
109
	}
110
	if($g['booting']) echo ".";
111
	// Check for encrypted config.xml
112
	encrypted_configxml();
113
	if(!$parse) {
114
		if(file_exists($g['tmp_path'] . '/config.cache')) {
115
			$config = unserialize(file_get_contents($g['tmp_path'] . '/config.cache'));
116
			if(is_null($config)) {
117
				unlock($lockkey);
118
				parse_config(true);
119
				$lockkey = lock('config');
120
			}
121
		} else {
122
			if(!file_exists($g['conf_path'] . "/config.xml")) {
123
				log_error("No config.xml found, attempting last known config restore.");
124
				file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
125
				$last_backup = discover_last_backup();
126
				if ($last_backup)
127
					restore_backup("/cf/conf/backup/{$last_backup}");
128
				else
129
					log_error("Could not restore config.xml.");
130
			}
131
			unlock($lockkey);
132
			$config = parse_config(true);
133
			$lockkey = lock('config');
134
		}
135
	} else {
136
		if(!file_exists($g['conf_path'] . "/config.xml")) {
137
			if($g['booting']) echo ".";
138
			log_error("No config.xml found, attempting last known config restore.");
139
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
140
			$last_backup = discover_last_backup();
141
			if ($last_backup)
142
				restore_backup("/cf/conf/backup/{$last_backup}");
143
			else
144
				log_error("Could not restore config.xml.");
145
		}
146
		$config = parse_xml_config($g['conf_path'] . '/config.xml', $g['xml_rootobj']);
147
		if($config == "-1") {
148
			$last_backup = discover_last_backup();
149
			if ($last_backup)
150
				restore_backup("/cf/conf/backup/{$last_backup}");
151
			else
152
				log_error(gettext("Could not restore config.xml."));
153
		}
154
		generate_config_cache($config);
155
	}
156
	if($g['booting']) echo ".";
157
	alias_make_table($config);
158
	$config_parsed = true;
159
	unlock($lockkey);
160

    
161
	return $config;
162
}
163

    
164
/****f* config/generate_config_cache
165
 * NAME
166
 *   generate_config_cache - Write serialized configuration to cache.
167
 * INPUTS
168
 *   $config	- array containing current firewall configuration
169
 * RESULT
170
 *   boolean	- true on completion
171
 ******/
172
function generate_config_cache($config) {
173
	global $g;
174

    
175
	$configcache = fopen($g['tmp_path'] . '/config.cache', "w");
176
	fwrite($configcache, serialize($config));
177
	fclose($configcache);
178
}
179

    
180
function discover_last_backup() {
181
        $backups = split("\n", `cd /cf/conf/backup && ls -ltr *.xml | awk '{print \$9}'`);
182
	$last_backup = "";
183
        foreach($backups as $backup)
184
        	if($backup)
185
	        	$last_backup = $backup;
186

    
187
        return $last_backup;
188
}
189

    
190
function restore_backup($file) {
191
	global $g;
192

    
193
	if (file_exists($file)) {
194
		conf_mount_rw();
195
		copy("$file","/cf/conf/config.xml");
196
		unlink_if_exists("{$g['tmp_path']}/config.cache");
197
		log_error("{$g['product_name']} is restoring the configuration $file");
198
		file_notice("config.xml", "{$g['product_name']} is restoring the configuration $file", "pfSenseConfigurator", "");
199
		conf_mount_ro();
200
	}
201
}
202

    
203
/****f* config/parse_config_bootup
204
 * NAME
205
 *   parse_config_bootup - Bootup-specific configuration checks.
206
 * RESULT
207
 *   null
208
 ******/
209
function parse_config_bootup() {
210
	global $config, $g, $noparseconfig;
211

    
212
	if($g['booting']) echo ".";
213

    
214
	$lockkey = lock('config');
215
	if (!$noparseconfig) {
216
		if (!file_exists("{$g['conf_path']}/config.xml")) {
217
			if ($g['booting']) {
218
				if (strstr($g['platform'], "cdrom")) {
219
					/* try copying the default config. to the floppy */
220
					echo "Resetting factory defaults...\n";
221
					reset_factory_defaults(true);
222
					if (file_exists("{$g['conf_path']}/config.xml")) {
223
						/* do nothing, we have a file. */
224
					} else {
225
						echo "No XML configuration file found - using factory defaults.\n";
226
						echo "Make sure that the configuration floppy disk with the conf/config.xml\n";
227
						echo "file is inserted. If it isn't, your configuration changes will be lost\n";
228
						echo "on reboot.\n";
229
					}
230
				} else {
231
					$last_backup = discover_last_backup();
232
					if($last_backup) {
233
						log_error("No config.xml found, attempting last known config restore.");
234
						file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
235
						restore_backup("/cf/conf/backup/{$last_backup}");
236
					}
237
					if(!file_exists("{$g['conf_path']}/config.xml")) {
238
						echo "XML configuration file not found.  {$g['product_name']} cannot continue booting.\n";
239
						mwexec("/sbin/halt");
240
						exit;
241
					}
242
					log_error("Last known config found and restored.  Please double check your configuration file for accuracy.");
243
					file_notice("config.xml", "Last known config found and restored.  Please double check your configuration file for accuracy.", "pfSenseConfigurator", "");
244
				}
245
			} else {
246
				unlock($lockkey);
247
				exit(0);
248
			}
249
		}
250
	}
251
	if (filesize("{$g['conf_path']}/config.xml") == 0) {
252
		$last_backup = discover_last_backup();
253
		if($last_backup) {
254
			log_error("No config.xml found, attempting last known config restore.");
255
			file_notice("config.xml", "No config.xml found, attempting last known config restore.", "pfSenseConfigurator", "");
256
			restore_backup("{$g['conf_path']}/backup/{$last_backup}");
257
		} else {
258
			unlock($lockkey);
259
			die("Config.xml is corrupted and is 0 bytes.  Could not restore a previous backup.");
260
		}
261
	}
262
	unlock($lockkey);
263
	parse_config(true);
264

    
265
	if ((float)$config['version'] > (float)$g['latest_config']) {
266
		echo <<<EOD
267

    
268

    
269
*******************************************************************************
270
* WARNING!                                                                    *
271
* The current configuration has been created with a newer version of {$g['product_name']}  *
272
* than this one! This can lead to serious misbehavior and even security       *
273
* holes! You are urged to either upgrade to a newer version of {$g['product_name']} or     *
274
* revert to the default configuration immediately!                            *
275
*******************************************************************************
276

    
277

    
278
EOD;
279
		}
280

    
281
	/* make alias table (for faster lookups) */
282
	alias_make_table($config);
283
}
284

    
285
/****f* config/conf_mount_rw
286
 * NAME
287
 *   conf_mount_rw - Mount filesystems read/write.
288
 * RESULT
289
 *   null
290
 ******/
291
/* mount flash card read/write */
292
function conf_mount_rw() {
293
	global $g;
294

    
295
	/* do not mount on cdrom platform */
296
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
297
		return;
298
		
299
	if (is_subsystem_dirty('mount'))
300
		return;
301

    
302
	$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
303
	if($status <> 0) {
304
		if($g['booting'])
305
			echo "Disk is dirty.  Running fsck -y\n";
306
		mwexec("/sbin/fsck -y {$g['cf_path']}");
307
		$status = mwexec("/sbin/mount -u -w {$g['cf_path']}");
308
	}
309

    
310
	/*    if the platform is soekris or wrap or pfSense, lets mount the
311
	 *    compact flash cards root.
312
         */
313
	if($g['platform'] == "wrap" or $g['platform'] == "net45xx"
314
	   or $g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
315
		$status = mwexec("/sbin/mount -u -w /");
316
		/* we could not mount this correctly.  kick off fsck */
317
		if($status <> 0) {
318
			log_error("File system is dirty.  Launching FSCK for /");
319
			mwexec("/sbin/fsck -y /");
320
			$status = mwexec("/sbin/mount -u -w /");
321
		}
322
	}
323
	
324
	mark_subsystem_dirty('mount');
325
}
326

    
327
/****f* config/conf_mount_ro
328
 * NAME
329
 *   conf_mount_ro - Mount filesystems readonly.
330
 * RESULT
331
 *   null
332
 ******/
333
function conf_mount_ro() {
334
	global $g;
335

    
336
	if($g['booting'] == true)
337
		return;
338

    
339
	/* firmare upgrade in progress */
340
	if (is_subsystem_dirty('firmwarelock'))
341
		return;
342

    
343
	/* do not umount if generating ssh keys */
344
	if (is_subsystem_dirty('sshdkeys'))
345
		return;
346

    
347
	/* do not umount on cdrom or pfSense platforms */
348
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
349
		return;
350

    
351
	if (!is_subsystem_dirty('mount'))
352
		return;
353

    
354
	clear_subsystem_dirty('mount');
355
	/* sync data, then force a remount of /cf */
356
	mwexec("/bin/sync");
357
	mwexec("/bin/sync");
358
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
359
	mwexec("/sbin/mount -u -r -f /");
360
}
361

    
362
/****f* config/convert_config
363
 * NAME
364
 *   convert_config - Attempt to update config.xml.
365
 * DESCRIPTION
366
 *   convert_config() reads the current global configuration
367
 *   and attempts to convert it to conform to the latest
368
 *   config.xml version. This allows major formatting changes
369
 *   to be made with a minimum of breakage.
370
 * RESULT
371
 *   null
372
 ******/
373
/* convert configuration, if necessary */
374
function convert_config() {
375
	global $config, $g;
376
	$now = date("H:i:s");
377
	log_error("Start Configuration upgrade at $now, set execution timeout to 15 minutes");
378
	ini_set("max_execution_time", "900");
379

    
380
	/* special case upgrades */
381
	/* fix every minute crontab bogons entry */
382
	$cron_item_count = count($config['cron']['item']);
383
	for($x=0; $x<$cron_item_count; $x++) {
384
		if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
385
			if($config['cron']['item'][$x]['hour'] == "*" ) {
386
		        $config['cron']['item'][$x]['hour'] = "3";
387
		 		write_config("Updated bogon update frequency to 3am");
388
		 		log_error("Updated bogon update frequency to 3am");
389
		 	}       
390
		}
391
	}
392
	if ($config['version'] == $g['latest_config'])
393
		return;		/* already at latest version */
394

    
395
	// Save off config version
396
	$prev_version = $config['version'];
397
	
398
	include_once('auth.inc');
399
	include_once('upgrade_config.inc');
400
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
401
	while ($config['version'] < $g['latest_config']) {
402
		$cur = $config['version'] * 10;
403
		$next = $cur + 1;
404
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
405
		$migration_function();
406
		$config['version'] = sprintf('%.1f', $next / 10);
407
		if($g['booting'])
408
			echo ".";
409
	}
410

    
411
	$now = date("H:i:s");
412
	log_error("Ended Configuration upgrade at $now");
413

    
414
	if ($prev_version != $config['version'])
415
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
416

    
417
	if($g['booting'])
418
		echo "Loading new configuration...";
419
}
420

    
421
/****f* config/write_config
422
 * NAME
423
 *   write_config - Backup and write the firewall configuration.
424
 * DESCRIPTION
425
 *   write_config() handles backing up the current configuration,
426
 *   applying changes, and regenerating the configuration cache.
427
 * INPUTS
428
 *   $desc	- string containing the a description of configuration changes
429
 *   $backup	- boolean: do not back up current configuration if false.
430
 * RESULT
431
 *   null
432
 ******/
433
/* save the system configuration */
434
function write_config($desc="Unknown", $backup = true) {
435
	global $config, $g;
436

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

    
440
	if($backup)
441
		backup_config();
442

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

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

    
450
	$config['revision']['description'] = $desc;
451
	$config['revision']['time'] = $changetime;
452

    
453
	$lockkey = lock('config');
454

    
455
	/* generate configuration XML */
456
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
457

    
458
	conf_mount_rw();
459

    
460
	/* write new configuration */
461
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
462
		log_error("WARNING: Config contents could not be save. Could not open file!");
463
		unlock($lockkey);
464
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
465
	}
466
	
467
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
468
		cleanup_backupcache(5, true);
469
	} else {
470
		cleanup_backupcache(30, true);
471
	}
472

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

    
476
	/* write config cache */
477
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
478
	if ($fd) {
479
		fwrite($fd, serialize($config));
480
		fclose($fd);
481
	}
482

    
483
	/* tell kernel to sync fs data */
484
	if (!$g['booting'])
485
		conf_mount_ro();
486

    
487
	unlock($lockkey);
488

    
489
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
490

    
491
	/* sync carp entries to other firewalls */
492
	carp_sync_client();
493

    
494
	if(is_dir("/usr/local/pkg/write_config")) {
495
		/* process packager manager custom rules */
496
		run_plugins("/usr/local/pkg/write_config/");
497
	}
498

    
499
	return $config;
500
}
501

    
502
/****f* config/reset_factory_defaults
503
 * NAME
504
 *   reset_factory_defaults - Reset the system to its default configuration.
505
 * RESULT
506
 *   integer	- indicates completion
507
 ******/
508
function reset_factory_defaults($lock = false) {
509
	global $g;
510

    
511
	if (!$lock)
512
		$lockkey = lock('config');
513
	conf_mount_rw();
514

    
515
	/* create conf directory, if necessary */
516
	safe_mkdir("{$g['cf_conf_path']}");
517

    
518
	/* clear out /conf */
519
	$dh = opendir($g['conf_path']);
520
	while ($filename = readdir($dh)) {
521
		if (($filename != ".") && ($filename != "..")) {
522
			unlink_if_exists($g['conf_path'] . "/" . $filename);
523
		}
524
	}
525
	closedir($dh);
526

    
527
	/* copy default configuration */
528
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
529

    
530
	/* call the wizard */
531
	touch("/conf/trigger_initial_wizard");
532
	conf_mount_ro();
533
	if (!$lock)
534
		unlock($lockkey);
535

    
536
	return 0;
537
}
538

    
539
function config_restore($conffile) {
540
	global $config, $g;
541

    
542
	if (!file_exists($conffile))
543
		return 1;
544

    
545
	conf_mount_rw();
546

    
547
	backup_config();
548

    
549
	$lockkey = lock('config');
550

    
551
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
552
	unlink_if_exists("{$g['tmp_path']}/config.cache");
553

    
554
	unlock($lockkey);
555

    
556
	$config = parse_config(true);
557

    
558
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
559

    
560
	conf_mount_ro();
561

    
562
	return 0;
563
}
564

    
565
function config_install($conffile) {
566
	global $config, $g;
567

    
568
	if (!file_exists($conffile))
569
		return 1;
570

    
571
	if (!config_validate("{$conffile}"))
572
		return 1;
573

    
574
	if($g['booting'] == true)
575
		echo "Installing configuration...\n";
576
	else
577
		log_error("Installing configuration ....");
578

    
579
	conf_mount_rw();
580
	$lockkey = lock('config');
581

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

    
584
	/* unlink cache file if it exists */
585
	if(file_exists("{$g['tmp_path']}/config.cache"))
586
		unlink("{$g['tmp_path']}/config.cache");
587

    
588
	unlock($lockkey);
589
	conf_mount_ro();
590

    
591
    return 0;
592
}
593

    
594
function config_validate($conffile) {
595

    
596
	global $g, $xmlerr;
597

    
598
	$xml_parser = xml_parser_create();
599

    
600
	if (!($fp = fopen($conffile, "r"))) {
601
		$xmlerr = "XML error: unable to open file";
602
		return false;
603
	}
604

    
605
	while ($data = fread($fp, 4096)) {
606
		if (!xml_parse($xml_parser, $data, feof($fp))) {
607
			$xmlerr = sprintf("%s at line %d",
608
						xml_error_string(xml_get_error_code($xml_parser)),
609
						xml_get_current_line_number($xml_parser));
610
			return false;
611
		}
612
	}
613
	xml_parser_free($xml_parser);
614

    
615
	fclose($fp);
616

    
617
	return true;
618
}
619

    
620
function set_networking_interfaces_ports() {
621
	global $noreboot;
622
	global $config;
623
	global $g;
624
	global $fp;
625

    
626
	$fp = fopen('php://stdin', 'r');
627

    
628
	$memory = get_memory();
629
	$avail = $memory[0];
630

    
631
	if($avail < $g['minimum_ram_warning']) {
632
		echo "\n\n\n";
633
		echo "DANGER!  WARNING!  ACHTUNG!\n\n";
634
		echo "{$g['product_name']} requires *AT LEAST* {$g['minimum_ram_warning_text']} RAM to function correctly.\n";
635
		echo "Only ({$avail}) MB RAM has been detected.\n";
636
		echo "\nPress ENTER to continue. ";
637
		fgets($fp);
638
		echo "\n";
639
	}
640

    
641
	$iflist = get_interface_list();
642

    
643
/* Function flow is based on $key and $auto_assign or the lack thereof */	
644
	$key = null;
645

    
646
/* Only present auto interface option if running from LiveCD and interface mismatch*/
647
	if ((ereg("cdrom", $g['platform'])) && is_interface_mismatch())
648
		$auto_assign = false;
649

    
650
	echo <<<EOD
651

    
652
Valid interfaces are:
653

    
654

    
655
EOD;
656

    
657
	if(!is_array($iflist)) {
658
		echo "No interfaces found!\n";
659
		$iflist = array();
660
	} else {
661
		foreach ($iflist as $iface => $ifa) {
662
			echo sprintf("% -6s%s%s\t%s\n", $iface, $ifa['mac'],
663
				$ifa['up'] ? "   (up)" : "   (down)", $ifa['dmesg']);
664
		}
665
	}
666

    
667
	if ($auto_assign) {
668
		echo <<<EOD
669
		
670
		!!! LiveCD Detected: Auto Interface Option !!!!
671
BEGIN MANUAL CONFIGURATION OR WE WILL PROCEED WITH AUTO CONFIGURATION.
672

    
673
EOD;
674
	}	
675
	
676
	echo <<<EOD
677

    
678
Do you want to set up VLANs first? 
679

    
680
If you are not going to use VLANs, or only for optional interfaces, you should
681
say no here and use the webConfigurator to configure VLANs later, if required.
682

    
683
Do you want to set up VLANs now [y|n]? 
684
EOD;
685

    
686
	if ($auto_assign) {
687
		$key = timeout();
688

    
689
	} else
690
		$key = chop(fgets($fp));
691

    
692
	if (!isset($key) and $auto_assign) {	// Auto Assign Interfaces
693
		do {
694
			echo <<<EOD
695

    
696
   !!! Auto Assigning Interfaces !!!
697

    
698
For installation purposes, you must plug in at least one NIC
699
for the LAN connection. If you plug in a second NIC it will be
700
assigned to WAN. Otherwise, we'll temporarily assign WAN to the
701
next available NIC found regardless of activity. You should
702
assign and configure the WAN interface according to your requirements
703

    
704
If you haven't plugged in any network cables yet,
705
now is the time to do so.
706
We'll keep trying until you do.
707

    
708
Searching for active interfaces...
709
 
710
EOD;
711
			unset($wanif, $lanif);
712

    
713
			$media_iflist = $plugged_in = array();
714
			$media_iflist = get_interface_list("media");
715
			foreach ($media_iflist as $iface => $ifa) {
716
				if ($ifa['up']) 
717
					$plugged_in[] = $iface;
718
				
719
			}
720

    
721
			$lanif = array_shift($plugged_in);
722
			$wanif = array_shift($plugged_in);
723

    
724
			if(isset($lanif) && !isset($wanif)) {
725
				foreach ($iflist as $iface => $ifa) {
726
					if ($iface != $lanif) {
727
						$wanif = $iface;
728
						break;
729
					}
730
				}
731
			}
732

    
733
			echo <<<EOD
734

    
735
Assigned WAN to : $wanif 
736
Assigned LAN to : $lanif
737

    
738
If you don't like this assignment,
739
press any key to go back to manual configuration. 
740

    
741
EOD;
742
			$key = timeout(20);
743
			if(isset($key))
744
				return;
745
		} while (!isset($wanif));
746

    
747
		$config['system']['enablesshd'] = 'enabled';	
748
		$key = 'y';
749

    
750
	} else {		//Manually assign interfaces	
751
		if (in_array($key, array('y', 'Y')))
752
			vlan_setup();
753
	
754
		if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
755
	
756
			echo "\n\nVLAN interfaces:\n\n";
757
			foreach ($config['vlans']['vlan'] as $vlan) {
758
	
759
				echo sprintf("% -16s%s\n", "{$vlan['if']}_vlan{$vlan['tag']}",
760
					"VLAN tag {$vlan['tag']}, parent interface {$vlan['if']}");
761
	
762
				$iflist[$vlan['if'] . '_vlan' . $vlan['tag']] = array();
763
			}
764
		}
765
	
766
		echo <<<EOD
767
	
768
*NOTE*  {$g['product_name']} requires {$g['minimum_nic_count_text']} assigned interfaces to function.
769
        If you do not have {$g['minimum_nic_count_text']} interfaces you CANNOT continue. 
770

    
771
        If you do not have at least {$g['minimum_nic_count']} *REAL* network interface cards
772
        or one interface with multiple VLANs then {$g['product_name']}
773
        *WILL NOT* function correctly.
774

    
775
If you do not know the names of your interfaces, you may choose to use
776
auto-detection. In that case, disconnect all interfaces now before
777
hitting 'a' to initiate auto detection.
778
	
779
EOD;
780
	
781
		do {
782
			echo "\nEnter the WAN interface name or 'a' for auto-detection: ";
783
			$wanif = chop(fgets($fp));
784
			if ($wanif === "") {
785
				return;
786
			}
787
			if ($wanif === "a")
788
				$wanif = autodetect_interface("WAN", $fp);
789
			else if (!array_key_exists($wanif, $iflist)) {
790
				echo "\nInvalid interface name '{$wanif}'\n";
791
				unset($wanif);
792
				continue;
793
			}
794
		} while (!$wanif);
795
	
796
		do {
797
			echo "\nEnter the LAN interface name or 'a' for auto-detection \n" .
798
			    "NOTE: this enables full Firewalling/NAT mode.\n" .
799
				"(or nothing if finished): ";
800
	
801
			$lanif = chop(fgets($fp));
802
			
803
			if($lanif == "exit") {
804
				exit;
805
			}
806
			
807
			if($lanif == "") {
808
				if($g['minimum_nic_count'] < 2) {
809
					break;	
810
				} else {
811
					fclose($fp);
812
					return;
813
				}
814
			}
815
	
816
			if ($lanif === "a")
817
				$lanif = autodetect_interface("LAN", $fp);
818
			else if (!array_key_exists($lanif, $iflist)) {
819
				echo "\nInvalid interface name '{$lanif}'\n";
820
				unset($lanif);
821
				continue;
822
			}
823
		} while (!$lanif);
824
	
825
		/* optional interfaces */
826
		$i = 0;
827
		$optif = array();
828
	
829
		if($lanif <> "") {
830
			while (1) {
831
				if ($optif[$i])
832
					$i++;
833
				$i1 = $i + 1;
834
		
835
				if($config['interfaces']['opt' . $i1]['descr'])
836
					echo "\nOptional interface {$i1} description found: {$config['interfaces']['opt' . $i1]['descr']}";
837
	
838
				echo "\nEnter the Optional {$i1} interface name or 'a' for auto-detection\n" .
839
					"(or nothing if finished): ";
840
		
841
				$optif[$i] = chop(fgets($fp));
842
		
843
				if ($optif[$i]) {
844
					if ($optif[$i] === "a") {
845
						$ad = autodetect_interface("Optional " . $i1, $fp);
846
						if ($ad)
847
							$optif[$i] = $ad;
848
						else
849
							unset($optif[$i]);
850
					} else if (!array_key_exists($optif[$i], $iflist)) {
851
						echo "\nInvalid interface name '{$optif[$i]}'\n";
852
						unset($optif[$i]);
853
						continue;
854
					}
855
				} else {
856
					unset($optif[$i]);
857
					break;
858
				}
859
			}
860
		}
861
		
862
		/* check for double assignments */
863
		$ifarr = array_merge(array($lanif, $wanif), $optif);
864
		
865
		for ($i = 0; $i < (count($ifarr)-1); $i++) {
866
			for ($j = ($i+1); $j < count($ifarr); $j++) {
867
				if ($ifarr[$i] == $ifarr[$j]) {
868
					echo <<<EOD
869
	
870
Error: you cannot assign the same interface name twice!
871
	
872
EOD;
873
					fclose($fp);
874
					return;
875
				}
876
			}
877
		}
878
	
879
		echo "\nThe interfaces will be assigned as follows: \n\n";
880
	
881
		if ($lanif != "")
882
			echo "LAN  -> " . $lanif . "\n";
883
		echo "WAN  -> " . $wanif . "\n";
884
		for ($i = 0; $i < count($optif); $i++) {
885
			echo "OPT" . ($i+1) . " -> " . $optif[$i] . "\n";
886
		}
887
	
888
		echo <<<EOD
889
	
890
Do you want to proceed [y|n]?
891
EOD;
892
			$key = chop(fgets($fp));		
893
	}
894

    
895
	if (in_array($key, array('y', 'Y'))) {
896
		if($lanif) {
897
			$config['interfaces']['lan']['if'] = $lanif;
898
		} elseif (!$g['booting'] && !$auto_assign) {
899

    
900
echo <<<EODD
901

    
902
You have chosen to remove the LAN interface.
903

    
904
Would you like to remove the LAN IP address and
905
unload the interface now? [y|n]? 
906
EODD;
907

    
908
				if (strcasecmp(chop(fgets($fp)), "y") == 0) {
909
					if($config['interfaces']['lan']['if'])
910
						mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
911
				}
912
				if(isset($config['interfaces']['lan']))
913
					unset($config['interfaces']['lan']);
914
				if(isset($config['dhcpd']['lan']))
915
					unset($config['dhcpd']['lan']);
916
				if(isset($config['interfaces']['lan']['if']))
917
					unset($config['interfaces']['lan']['if']);
918
				if(isset($config['interfaces']['wan']['blockpriv']))
919
					unset($config['interfaces']['wan']['blockpriv']);
920
				if(isset($config['shaper']))
921
					unset($config['shaper']);
922
				if(isset($config['ezshaper']))
923
					unset($config['ezshaper']);
924
				if(isset($config['nat']))
925
					unset($config['nat']);				
926
		} else {
927
			if(isset($config['interfaces']['lan']['if']))
928
				mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
929
			if(isset($config['interfaces']['lan']))
930
				unset($config['interfaces']['lan']);
931
			if(isset($config['dhcpd']['lan']))
932
				unset($config['dhcpd']['lan']);
933
			if(isset($config['interfaces']['lan']['if']))
934
				unset($config['interfaces']['lan']['if']);
935
			if(isset($config['interfaces']['wan']['blockpriv']))
936
				unset($config['interfaces']['wan']['blockpriv']);
937
			if(isset($config['shaper']))
938
				unset($config['shaper']);
939
			if(isset($config['ezshaper']))
940
				unset($config['ezshaper']);
941
			if(isset($config['nat']))
942
				unset($config['nat']);				
943
		}
944
		if (preg_match($g['wireless_regex'], $lanif)) {
945
			if (is_array($config['interfaces']['lan']) &&
946
				(!is_array($config['interfaces']['lan']['wireless'])))
947
				$config['interfaces']['lan']['wireless'] = array();
948
		} else {
949
			unset($config['interfaces']['lan']['wireless']);
950
		}
951

    
952
		$config['interfaces']['wan']['if'] = $wanif;
953
		if (preg_match($g['wireless_regex'], $wanif)) {
954
			if (is_array($config['interfaces']['lan']) &&
955
				(!is_array($config['interfaces']['wan']['wireless'])))
956
				$config['interfaces']['wan']['wireless'] = array();
957
		} else {
958
			unset($config['interfaces']['wan']['wireless']);
959
		}
960

    
961
		for ($i = 0; $i < count($optif); $i++) {
962
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
963
				$config['interfaces']['opt' . ($i+1)] = array();
964

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

    
967
			/* wireless interface? */
968
			if (preg_match($g['wireless_regex'], $optif[$i])) {
969
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
970
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
971
			} else {
972
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
973
			}
974

    
975
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
976
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
977
		}
978

    
979
		/* remove all other (old) optional interfaces */
980
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
981
			unset($config['interfaces']['opt' . ($i+1)]);
982

    
983
		echo "\nWriting configuration...";
984
		write_config();
985
		echo "done.\n";
986

    
987
		echo <<<EOD
988

    
989

    
990

    
991
EOD;
992

    
993
		fclose($fp);
994
		if($g['booting'])
995
			return;
996

    
997
		echo "One moment while we reload the settings...";
998

    
999
		$g['booting'] = false;
1000

    
1001
		/* XXX: ermal - disable it for now this is used during bootup at best so shouldn't be needed.
1002
		 * 		For now just comment it out and later remove it completely.
1003
		 * resync everything 
1004
			reload_all_sync();
1005
		 */
1006

    
1007
		echo " done!\n";
1008

    
1009
		touch("{$g['tmp_path']}/assign_complete");
1010

    
1011
	}
1012
}
1013

    
1014
function autodetect_interface($ifname, $fp) {
1015
	$iflist_prev = get_interface_list("media");
1016
	echo <<<EOD
1017

    
1018
Connect the {$ifname} interface now and make sure that the link is up.
1019
Then press ENTER to continue.
1020

    
1021
EOD;
1022
	fgets($fp);
1023
	$iflist = get_interface_list("media");
1024

    
1025
	foreach ($iflist_prev as $ifn => $ifa) {
1026
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1027
			echo "Detected link-up on interface {$ifn}.\n";
1028
			return $ifn;
1029
		}
1030
	}
1031

    
1032
	echo "No link-up detected.\n";
1033

    
1034
	return null;
1035
}
1036

    
1037
function vlan_setup() {
1038
	global $iflist, $config, $g, $fp;
1039

    
1040
	$iflist = get_interface_list();
1041

    
1042
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1043

    
1044
	echo <<<EOD
1045

    
1046
WARNING: all existing VLANs will be cleared if you proceed!
1047

    
1048
Do you want to proceed [y|n]?
1049
EOD;
1050

    
1051
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1052
		return;
1053
	}
1054

    
1055
	$config['vlans']['vlan'] = array();
1056
	echo "\n";
1057

    
1058
	$vlanif = 0;
1059

    
1060
	while (1) {
1061
		$vlan = array();
1062

    
1063
		echo "\n\nVLAN Capable interfaces:\n\n";
1064
		if(!is_array($iflist)) {
1065
			echo "No interfaces found!\n";
1066
		} else {
1067
			$vlan_capable=0;
1068
			foreach ($iflist as $iface => $ifa) {
1069
				if (is_jumbo_capable($iface)) {
1070
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1071
						$ifa['up'] ? "   (up)" : "");
1072
					$vlan_capable++;
1073
				}
1074
			}
1075
		}
1076

    
1077
		if($vlan_capable == 0) {
1078
			echo "No VLAN capable interfaces detected.\n";
1079
			return;
1080
		}
1081

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

    
1085
		if ($vlan['if']) {
1086
			if (!array_key_exists($vlan['if'], $iflist) or
1087
			    !is_jumbo_capable($vlan['if'])) {
1088
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1089
				continue;
1090
			}
1091
		} else {
1092
			break;
1093
		}
1094

    
1095
		echo "Enter the VLAN tag (1-4094): ";
1096
		$vlan['tag'] = chop(fgets($fp));
1097
		$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
1098
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1099
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1100
			continue;
1101
		}
1102
		
1103
		$config['vlans']['vlan'][] = $vlan;
1104
		$vlanif++;
1105
	}
1106
}
1107

    
1108
function cleanup_backupcache($revisions = 30, $lock = false) {
1109
	global $g;
1110
	$i = false;
1111
	
1112
	if (!$lock)
1113
		$lockkey = lock('config');
1114
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1115
		conf_mount_rw();
1116
		$backups = get_backups();
1117
		$newbaks = array();
1118
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1119
		$baktimes = $backups['versions'];
1120
		$tocache = array();
1121
		unset($backups['versions']);
1122
   		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1123
   			if(filesize($backup) == 0) {
1124
   				unlink($backup);
1125
   				continue;
1126
   			}
1127
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1128
            if(!in_array($tocheck, $baktimes)) {
1129
				$i = true;
1130
				if($g['booting'])
1131
					echo ".";
1132
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1133
				if($newxml == "-1") {
1134
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1135
					unlink($backup);
1136
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1137
					continue;
1138
				}
1139
				if($newxml['revision']['description'] == "")
1140
					$newxml['revision']['description'] = "Unknown";
1141
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1142
			}
1143
    	}
1144
		foreach($backups as $checkbak) {
1145

    
1146
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1147
				$newbaks[] = $checkbak;
1148
			} else {
1149
				$i = true;
1150
				if($g['booting']) print " " . $tocheck . "r";
1151
			}
1152
		}
1153
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1154
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1155
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1156
			foreach($toslice as $sliced)
1157
				$newcache[$sliced] = $tocache[$sliced];
1158
			foreach($tocache as $version => $versioninfo) {
1159
				if(!in_array($version, array_keys($newcache))) {
1160
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1161
					if($g['booting']) print " " . $tocheck . "d";
1162
				}
1163
			}
1164
			$tocache = $newcache;
1165
		}
1166
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1167
        fwrite($bakout, serialize($tocache));
1168
		fclose($bakout);
1169
		conf_mount_ro();
1170
	}
1171
	if($g['booting'] && $i)
1172
		print "done.\n";
1173
	if (!$lock)
1174
		unlock($lockkey);
1175
}
1176

    
1177
function get_backups() {
1178
	global $g;
1179
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1180
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1181
		$bakvers = array_keys($confvers);
1182
		$toreturn = array();
1183
		sort($bakvers);
1184
		// 	$bakvers = array_reverse($bakvers);
1185
		foreach(array_reverse($bakvers) as $bakver)
1186
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1187
	} else {
1188
		return false;
1189
	}
1190
	$toreturn['versions'] = $bakvers;
1191
	return $toreturn;
1192
}
1193

    
1194
function backup_config() {
1195
	global $config, $g;
1196

    
1197
	if($g['platform'] == "cdrom")
1198
		return;
1199

    
1200
	conf_mount_rw();
1201

    
1202
	/* Create backup directory if needed */
1203
	safe_mkdir("{$g['cf_conf_path']}/backup");
1204

    
1205
    if($config['revision']['time'] == "") {
1206
            $baktime = 0;
1207
    } else {
1208
            $baktime = $config['revision']['time'];
1209
    }
1210
    if($config['revision']['description'] == "") {
1211
            $bakdesc = "Unknown";
1212
    } else {
1213
            $bakdesc = $config['revision']['description'];
1214
    }
1215
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1216
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1217
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1218
    } else {
1219
            $backupcache = array();
1220
    }
1221
    $backupcache[$baktime] = array('description' => $bakdesc);
1222
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1223
    fwrite($bakout, serialize($backupcache));
1224
    fclose($bakout);
1225

    
1226
	conf_mount_ro();
1227

    
1228
	return true;
1229
}
1230

    
1231
function set_device_perms() {
1232
	$devices = array(
1233
		'pf'	=> array(	'user'	=> 'proxy',
1234
					'group'	=> 'proxy',
1235
					'mode'	=> 0660),
1236
		);
1237

    
1238
	foreach ($devices as $name => $attr) {
1239
		$path = "/dev/$name";
1240
		if (file_exists($path)) {
1241
			chown($path, $attr['user']);
1242
			chgrp($path, $attr['group']);
1243
			chmod($path, $attr['mode']);
1244
		}
1245
	}
1246
}
1247

    
1248
?>
(11-11/50)