Project

General

Profile

Download (34.5 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", "w");
72
						fwrite($fd, $data);
73
						fclose($fd);
74
						echo "\nConfig.xml unlocked.\n";
75
						fclose($fp);
76
					} else {
77
						echo "\nInvalid password entered.  Please try again.\n";
78
					}
79
				}
80
			}
81
		}
82
	}
83
}
84

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

    
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
	$fd = fopen("{$g['conf_path']}/config.xml", "w");
462
        if (!$fd) {
463
                // Unable to open temporary file for writing
464
		log_error("WARNING: Config contents could not be save. Could not open file!");
465
		unlock($lockkey);
466
                return false;
467
        }
468
        if (!fwrite($fd, $xmlconfig)) {
469
                // Unable to write to temporary file
470
		log_error("WARNING: Config contents could not be written on file.");
471
                fclose($fd);
472
		unlock($lockkey);
473
                return false;
474
        }
475
        fclose($fd);
476

    
477
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
478
		cleanup_backupcache(5, true);
479
	} else {
480
		cleanup_backupcache(30, true);
481
	}
482

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

    
486
	/* write config cache */
487
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
488
	if ($fd) {
489
		fwrite($fd, serialize($config));
490
		fclose($fd);
491
	}
492

    
493
	/* tell kernel to sync fs data */
494
	if (!$g['booting'])
495
		conf_mount_ro();
496

    
497
	unlock($lockkey);
498

    
499
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
500
	/* sync carp entries to other firewalls */
501
        carp_sync_client();
502

    
503
	if(is_dir("/usr/local/pkg/write_config")) {
504
		/* process packager manager custom rules */
505
		run_plugins("/usr/local/pkg/write_config/");
506
	}
507

    
508
	return $config;
509
}
510

    
511
/****f* config/reset_factory_defaults
512
 * NAME
513
 *   reset_factory_defaults - Reset the system to its default configuration.
514
 * RESULT
515
 *   integer	- indicates completion
516
 ******/
517
function reset_factory_defaults($lock = false) {
518
	global $g;
519

    
520
	if (!$lock)
521
		$lockkey = lock('config');
522
	conf_mount_rw();
523

    
524
	/* create conf directory, if necessary */
525
	safe_mkdir("{$g['cf_conf_path']}");
526

    
527
	/* clear out /conf */
528
	$dh = opendir($g['conf_path']);
529
	while ($filename = readdir($dh)) {
530
		if (($filename != ".") && ($filename != "..")) {
531
			unlink_if_exists($g['conf_path'] . "/" . $filename);
532
		}
533
	}
534
	closedir($dh);
535

    
536
	/* copy default configuration */
537
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
538

    
539
	/* call the wizard */
540
	touch("/conf/trigger_initial_wizard");
541
	conf_mount_ro();
542
	if (!$lock)
543
		unlock($lockkey);
544

    
545
	return 0;
546
}
547

    
548
function config_restore($conffile) {
549
	global $config, $g;
550

    
551
	if (!file_exists($conffile))
552
		return 1;
553

    
554
	conf_mount_rw();
555

    
556
	backup_config();
557

    
558
	$lockkey = lock('config');
559

    
560
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
561
	unlink_if_exists("{$g['tmp_path']}/config.cache");
562

    
563
	unlock($lockkey);
564

    
565
	$config = parse_config(true);
566

    
567
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
568

    
569
	conf_mount_ro();
570

    
571
	return 0;
572
}
573

    
574
function config_install($conffile) {
575
	global $config, $g;
576

    
577
	if (!file_exists($conffile))
578
		return 1;
579

    
580
	if (!config_validate("{$conffile}"))
581
		return 1;
582

    
583
	if($g['booting'] == true)
584
		echo "Installing configuration...\n";
585
	else
586
		log_error("Installing configuration ....");
587

    
588
	conf_mount_rw();
589
	$lockkey = lock('config');
590

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

    
593
	/* unlink cache file if it exists */
594
	if(file_exists("{$g['tmp_path']}/config.cache"))
595
		unlink("{$g['tmp_path']}/config.cache");
596

    
597
	unlock($lockkey);
598
	conf_mount_ro();
599

    
600
    return 0;
601
}
602

    
603
function config_validate($conffile) {
604

    
605
	global $g, $xmlerr;
606

    
607
	$xml_parser = xml_parser_create();
608

    
609
	if (!($fp = fopen($conffile, "r"))) {
610
		$xmlerr = "XML error: unable to open file";
611
		return false;
612
	}
613

    
614
	while ($data = fread($fp, 4096)) {
615
		if (!xml_parse($xml_parser, $data, feof($fp))) {
616
			$xmlerr = sprintf("%s at line %d",
617
						xml_error_string(xml_get_error_code($xml_parser)),
618
						xml_get_current_line_number($xml_parser));
619
			return false;
620
		}
621
	}
622
	xml_parser_free($xml_parser);
623

    
624
	fclose($fp);
625

    
626
	return true;
627
}
628

    
629
function set_networking_interfaces_ports() {
630
	global $noreboot;
631
	global $config;
632
	global $g;
633
	global $fp;
634

    
635
	$fp = fopen('php://stdin', 'r');
636

    
637
	$memory = get_memory();
638
	$avail = $memory[0];
639

    
640
	if($avail < $g['minimum_ram_warning']) {
641
		echo "\n\n\n";
642
		echo "DANGER!  WARNING!  ACHTUNG!\n\n";
643
		echo "{$g['product_name']} requires *AT LEAST* {$g['minimum_ram_warning_text']} RAM to function correctly.\n";
644
		echo "Only ({$avail}) MB RAM has been detected.\n";
645
		echo "\nPress ENTER to continue. ";
646
		fgets($fp);
647
		echo "\n";
648
	}
649

    
650
	$iflist = get_interface_list();
651

    
652
/* Function flow is based on $key and $auto_assign or the lack thereof */	
653
	$key = null;
654

    
655
/* Only present auto interface option if running from LiveCD and interface mismatch*/
656
	if ((ereg("cdrom", $g['platform'])) && is_interface_mismatch())
657
		$auto_assign = false;
658

    
659
	echo <<<EOD
660

    
661
Valid interfaces are:
662

    
663

    
664
EOD;
665

    
666
	if(!is_array($iflist)) {
667
		echo "No interfaces found!\n";
668
		$iflist = array();
669
	} else {
670
		foreach ($iflist as $iface => $ifa) {
671
			echo sprintf("% -6s%s%s\t%s\n", $iface, $ifa['mac'],
672
				$ifa['up'] ? "   (up)" : "   (down)", $ifa['dmesg']);
673
		}
674
	}
675

    
676
	if ($auto_assign) {
677
		echo <<<EOD
678
		
679
		!!! LiveCD Detected: Auto Interface Option !!!!
680
BEGIN MANUAL CONFIGURATION OR WE WILL PROCEED WITH AUTO CONFIGURATION.
681

    
682
EOD;
683
	}	
684
	
685
	echo <<<EOD
686

    
687
Do you want to set up VLANs first? 
688

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

    
692
Do you want to set up VLANs now [y|n]? 
693
EOD;
694

    
695
	if ($auto_assign) {
696
		$key = timeout();
697

    
698
	} else
699
		$key = chop(fgets($fp));
700

    
701
	if (!isset($key) and $auto_assign) {	// Auto Assign Interfaces
702
		do {
703
			echo <<<EOD
704

    
705
   !!! Auto Assigning Interfaces !!!
706

    
707
For installation purposes, you must plug in at least one NIC
708
for the LAN connection. If you plug in a second NIC it will be
709
assigned to WAN. Otherwise, we'll temporarily assign WAN to the
710
next available NIC found regardless of activity. You should
711
assign and configure the WAN interface according to your requirements
712

    
713
If you haven't plugged in any network cables yet,
714
now is the time to do so.
715
We'll keep trying until you do.
716

    
717
Searching for active interfaces...
718
 
719
EOD;
720
			unset($wanif, $lanif);
721

    
722
			$media_iflist = $plugged_in = array();
723
			$media_iflist = get_interface_list("media");
724
			foreach ($media_iflist as $iface => $ifa) {
725
				if ($ifa['up']) 
726
					$plugged_in[] = $iface;
727
				
728
			}
729

    
730
			$lanif = array_shift($plugged_in);
731
			$wanif = array_shift($plugged_in);
732

    
733
			if(isset($lanif) && !isset($wanif)) {
734
				foreach ($iflist as $iface => $ifa) {
735
					if ($iface != $lanif) {
736
						$wanif = $iface;
737
						break;
738
					}
739
				}
740
			}
741

    
742
			echo <<<EOD
743

    
744
Assigned WAN to : $wanif 
745
Assigned LAN to : $lanif
746

    
747
If you don't like this assignment,
748
press any key to go back to manual configuration. 
749

    
750
EOD;
751
			$key = timeout(20);
752
			if(isset($key))
753
				return;
754
		} while (!isset($wanif));
755

    
756
		$config['system']['enablesshd'] = 'enabled';	
757
		$key = 'y';
758

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

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

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

    
904
	if (in_array($key, array('y', 'Y'))) {
905
		if($lanif) {
906
			$config['interfaces']['lan']['if'] = $lanif;
907
		} elseif (!$g['booting'] && !$auto_assign) {
908

    
909
echo <<<EODD
910

    
911
You have chosen to remove the LAN interface.
912

    
913
Would you like to remove the LAN IP address and
914
unload the interface now? [y|n]? 
915
EODD;
916

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

    
961
		$config['interfaces']['wan']['if'] = $wanif;
962
		if (preg_match($g['wireless_regex'], $wanif)) {
963
			if (is_array($config['interfaces']['lan']) &&
964
				(!is_array($config['interfaces']['wan']['wireless'])))
965
				$config['interfaces']['wan']['wireless'] = array();
966
		} else {
967
			unset($config['interfaces']['wan']['wireless']);
968
		}
969

    
970
		for ($i = 0; $i < count($optif); $i++) {
971
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
972
				$config['interfaces']['opt' . ($i+1)] = array();
973

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

    
976
			/* wireless interface? */
977
			if (preg_match($g['wireless_regex'], $optif[$i])) {
978
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
979
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
980
			} else {
981
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
982
			}
983

    
984
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
985
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
986
		}
987

    
988
		/* remove all other (old) optional interfaces */
989
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
990
			unset($config['interfaces']['opt' . ($i+1)]);
991

    
992
		echo "\nWriting configuration...";
993
		write_config();
994
		echo "done.\n";
995

    
996
		echo <<<EOD
997

    
998

    
999

    
1000
EOD;
1001

    
1002
		fclose($fp);
1003
		if($g['booting'])
1004
			return;
1005

    
1006
		echo "One moment while we reload the settings...";
1007

    
1008
		$g['booting'] = false;
1009

    
1010
		/* XXX: ermal - disable it for now this is used during bootup at best so shouldn't be needed.
1011
		 * 		For now just comment it out and later remove it completely.
1012
		 * resync everything 
1013
			reload_all_sync();
1014
		 */
1015

    
1016
		echo " done!\n";
1017

    
1018
		touch("{$g['tmp_path']}/assign_complete");
1019

    
1020
	}
1021
}
1022

    
1023
function autodetect_interface($ifname, $fp) {
1024
	$iflist_prev = get_interface_list("media");
1025
	echo <<<EOD
1026

    
1027
Connect the {$ifname} interface now and make sure that the link is up.
1028
Then press ENTER to continue.
1029

    
1030
EOD;
1031
	fgets($fp);
1032
	$iflist = get_interface_list("media");
1033

    
1034
	foreach ($iflist_prev as $ifn => $ifa) {
1035
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1036
			echo "Detected link-up on interface {$ifn}.\n";
1037
			return $ifn;
1038
		}
1039
	}
1040

    
1041
	echo "No link-up detected.\n";
1042

    
1043
	return null;
1044
}
1045

    
1046
function vlan_setup() {
1047
	global $iflist, $config, $g, $fp;
1048

    
1049
	$iflist = get_interface_list();
1050

    
1051
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1052

    
1053
	echo <<<EOD
1054

    
1055
WARNING: all existing VLANs will be cleared if you proceed!
1056

    
1057
Do you want to proceed [y|n]?
1058
EOD;
1059

    
1060
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1061
		return;
1062
	}
1063

    
1064
	$config['vlans']['vlan'] = array();
1065
	echo "\n";
1066

    
1067
	$vlanif = 0;
1068

    
1069
	while (1) {
1070
		$vlan = array();
1071

    
1072
		echo "\n\nVLAN Capable interfaces:\n\n";
1073
		if(!is_array($iflist)) {
1074
			echo "No interfaces found!\n";
1075
		} else {
1076
			$vlan_capable=0;
1077
			foreach ($iflist as $iface => $ifa) {
1078
				if (is_jumbo_capable($iface)) {
1079
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1080
						$ifa['up'] ? "   (up)" : "");
1081
					$vlan_capable++;
1082
				}
1083
			}
1084
		}
1085

    
1086
		if($vlan_capable == 0) {
1087
			echo "No VLAN capable interfaces detected.\n";
1088
			return;
1089
		}
1090

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

    
1094
		if ($vlan['if']) {
1095
			if (!array_key_exists($vlan['if'], $iflist) or
1096
			    !is_jumbo_capable($vlan['if'])) {
1097
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1098
				continue;
1099
			}
1100
		} else {
1101
			break;
1102
		}
1103

    
1104
		echo "Enter the VLAN tag (1-4094): ";
1105
		$vlan['tag'] = chop(fgets($fp));
1106
		$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
1107
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1108
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1109
			continue;
1110
		}
1111
		
1112
		$config['vlans']['vlan'][] = $vlan;
1113
		$vlanif++;
1114
	}
1115
}
1116

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

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

    
1186
function get_backups() {
1187
	global $g;
1188
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1189
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1190
		$bakvers = array_keys($confvers);
1191
		$toreturn = array();
1192
		sort($bakvers);
1193
		// 	$bakvers = array_reverse($bakvers);
1194
		foreach(array_reverse($bakvers) as $bakver)
1195
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1196
	} else {
1197
		return false;
1198
	}
1199
	$toreturn['versions'] = $bakvers;
1200
	return $toreturn;
1201
}
1202

    
1203
function backup_config() {
1204
	global $config, $g;
1205

    
1206
	if($g['platform'] == "cdrom")
1207
		return;
1208

    
1209
	conf_mount_rw();
1210

    
1211
	/* Create backup directory if needed */
1212
	safe_mkdir("{$g['cf_conf_path']}/backup");
1213

    
1214
    if($config['revision']['time'] == "") {
1215
            $baktime = 0;
1216
    } else {
1217
            $baktime = $config['revision']['time'];
1218
    }
1219
    if($config['revision']['description'] == "") {
1220
            $bakdesc = "Unknown";
1221
    } else {
1222
            $bakdesc = $config['revision']['description'];
1223
    }
1224
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1225
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1226
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1227
    } else {
1228
            $backupcache = array();
1229
    }
1230
    $backupcache[$baktime] = array('description' => $bakdesc);
1231
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1232
    fwrite($bakout, serialize($backupcache));
1233
    fclose($bakout);
1234

    
1235
	conf_mount_ro();
1236

    
1237
	return true;
1238
}
1239

    
1240
function set_device_perms() {
1241
	$devices = array(
1242
		'pf'	=> array(	'user'	=> 'proxy',
1243
					'group'	=> 'proxy',
1244
					'mode'	=> 0660),
1245
		);
1246

    
1247
	foreach ($devices as $name => $attr) {
1248
		$path = "/dev/$name";
1249
		if (file_exists($path)) {
1250
			chown($path, $attr['user']);
1251
			chgrp($path, $attr['group']);
1252
			chmod($path, $attr['mode']);
1253
		}
1254
	}
1255
}
1256

    
1257
?>
(11-11/51)