Project

General

Profile

Download (34.4 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('upgrade_config.inc');
399
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
400
	while ($config['version'] < $g['latest_config']) {
401
		$cur = $config['version'] * 10;
402
		$next = $cur + 1;
403
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
404
		$migration_function();
405
		$config['version'] = sprintf('%.1f', $next / 10);
406
		echo ".";
407
	}
408

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

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

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

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

    
435
	if($backup)
436
		backup_config();
437

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

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

    
445
	$config['revision']['description'] = $desc;
446
	$config['revision']['time'] = $changetime;
447

    
448
	$lockkey = lock('config');
449

    
450
	/* generate configuration XML */
451
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
452

    
453
	conf_mount_rw();
454

    
455
	/* write new configuration */
456
	$fd = fopen("{$g['cf_conf_path']}/config.xml", "w");
457
        if (!$fd) {
458
                // Unable to open temporary file for writing
459
		log_error("WARNING: Config contents could not be save. Could not open file!");
460
		unlock($lockkey);
461
                return false;
462
        }
463
        if (!fwrite($fd, $xmlconfig)) {
464
                // Unable to write to temporary file
465
		log_error("WARNING: Config contents could not be written on file.");
466
                fclose($fd);
467
		unlock($lockkey);
468
                return false;
469
        }
470
        fclose($fd);
471

    
472
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
473
		cleanup_backupcache(5, true);
474
	} else {
475
		cleanup_backupcache(30, true);
476
	}
477

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

    
481
	/* write config cache */
482
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
483
	if ($fd) {
484
		fwrite($fd, serialize($config));
485
		fclose($fd);
486
	}
487

    
488
	/* tell kernel to sync fs data */
489
	if (!$g['booting'])
490
		conf_mount_ro();
491
	unlock($lockkey);
492

    
493
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
494
	/* sync carp entries to other firewalls */
495
        carp_sync_client();
496

    
497
	if(is_dir("/usr/local/pkg/write_config")) {
498
		/* process packager manager custom rules */
499
		run_plugins("/usr/local/pkg/write_config/");
500
	}
501

    
502
	return $config;
503
}
504

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

    
514
	if (!$lock)
515
		$lockkey = lock('config');
516
	conf_mount_rw();
517

    
518
	/* create conf directory, if necessary */
519
	safe_mkdir("{$g['cf_conf_path']}");
520

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

    
530
	/* copy default configuration */
531
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
532

    
533
	/* call the wizard */
534
	touch("/conf/trigger_initial_wizard");
535
	conf_mount_ro();
536
	if (!$lock)
537
		unlock($lockkey);
538

    
539
	return 0;
540
}
541

    
542
function config_restore($conffile) {
543
	global $config, $g;
544

    
545
	if (!file_exists($conffile))
546
		return 1;
547

    
548
	conf_mount_rw();
549

    
550
	backup_config();
551

    
552
	$lockkey = lock('config');
553

    
554
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
555
	unlink_if_exists("{$g['tmp_path']}/config.cache");
556

    
557
	unlock($lockkey);
558

    
559
	$config = parse_config(true);
560

    
561
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
562

    
563
	conf_mount_ro();
564

    
565
	return 0;
566
}
567

    
568
function config_install($conffile) {
569
	global $config, $g;
570

    
571
	if (!file_exists($conffile))
572
		return 1;
573

    
574
	if (!config_validate("{$conffile}"))
575
		return 1;
576

    
577
	if($g['booting'] == true)
578
		echo "Installing configuration...\n";
579
	else
580
		log_error("Installing configuration ....");
581

    
582
	conf_mount_rw();
583
	$lockkey = lock('config');
584

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

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

    
591
	unlock($lockkey);
592
	conf_mount_ro();
593

    
594
    return 0;
595
}
596

    
597
function config_validate($conffile) {
598

    
599
	global $g, $xmlerr;
600

    
601
	$xml_parser = xml_parser_create();
602

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

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

    
618
	fclose($fp);
619

    
620
	return true;
621
}
622

    
623
function set_networking_interfaces_ports() {
624
	global $noreboot;
625
	global $config;
626
	global $g;
627
	global $fp;
628

    
629
	$fp = fopen('php://stdin', 'r');
630

    
631
	$memory = get_memory();
632
	$avail = $memory[0];
633

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

    
644
	$iflist = get_interface_list();
645

    
646
/* Function flow is based on $key and $auto_assign or the lack thereof */	
647
	$key = null;
648

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

    
653
	echo <<<EOD
654

    
655
Valid interfaces are:
656

    
657

    
658
EOD;
659

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

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

    
676
EOD;
677
	}	
678
	
679
	echo <<<EOD
680

    
681
Do you want to set up VLANs first? 
682

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

    
686
Do you want to set up VLANs now [y|n]? 
687
EOD;
688

    
689
	if ($auto_assign) {
690
		$key = timeout();
691

    
692
	} else
693
		$key = chop(fgets($fp));
694

    
695
	if (!isset($key) and $auto_assign) {	// Auto Assign Interfaces
696
		do {
697
			echo <<<EOD
698

    
699
   !!! Auto Assigning Interfaces !!!
700

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

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

    
711
Searching for active interfaces...
712
 
713
EOD;
714
			unset($wanif, $lanif);
715

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

    
724
			$lanif = array_shift($plugged_in);
725
			$wanif = array_shift($plugged_in);
726

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

    
736
			echo <<<EOD
737

    
738
Assigned WAN to : $wanif 
739
Assigned LAN to : $lanif
740

    
741
If you don't like this assignment,
742
press any key to go back to manual configuration. 
743

    
744
EOD;
745
			$key = timeout(20);
746
			if(isset($key))
747
				return;
748
		} while (!isset($wanif));
749

    
750
		$config['system']['enablesshd'] = 'enabled';	
751
		$key = 'y';
752

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

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

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

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

    
903
echo <<<EODD
904

    
905
You have chosen to remove the LAN interface.
906

    
907
Would you like to remove the LAN IP address and
908
unload the interface now? [y|n]? 
909
EODD;
910

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

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

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

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

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

    
978
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
979
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
980
		}
981

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

    
986
		echo "\nWriting configuration...";
987
		write_config();
988
		echo "done.\n";
989

    
990
		echo <<<EOD
991

    
992

    
993

    
994
EOD;
995

    
996
		fclose($fp);
997
		if($g['booting'])
998
			return;
999

    
1000
		echo "One moment while we reload the settings...";
1001

    
1002
		$g['booting'] = false;
1003

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

    
1010
		echo " done!\n";
1011

    
1012
		touch("{$g['tmp_path']}/assign_complete");
1013

    
1014
	}
1015
}
1016

    
1017
function autodetect_interface($ifname, $fp) {
1018
	$iflist_prev = get_interface_list("media");
1019
	echo <<<EOD
1020

    
1021
Connect the {$ifname} interface now and make sure that the link is up.
1022
Then press ENTER to continue.
1023

    
1024
EOD;
1025
	fgets($fp);
1026
	$iflist = get_interface_list("media");
1027

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

    
1035
	echo "No link-up detected.\n";
1036

    
1037
	return null;
1038
}
1039

    
1040
function vlan_setup() {
1041
	global $iflist, $config, $g, $fp;
1042

    
1043
	$iflist = get_interface_list();
1044

    
1045
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1046

    
1047
	echo <<<EOD
1048

    
1049
WARNING: all existing VLANs will be cleared if you proceed!
1050

    
1051
Do you want to proceed [y|n]?
1052
EOD;
1053

    
1054
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1055
		return;
1056
	}
1057

    
1058
	$config['vlans']['vlan'] = array();
1059
	echo "\n";
1060

    
1061
	$vlanif = 0;
1062

    
1063
	while (1) {
1064
		$vlan = array();
1065

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

    
1080
		if($vlan_capable == 0) {
1081
			echo "No VLAN capable interfaces detected.\n";
1082
			return;
1083
		}
1084

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

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

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

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

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

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

    
1197
function backup_config() {
1198
	global $config, $g;
1199

    
1200
	if($g['platform'] == "cdrom")
1201
		return;
1202

    
1203
	conf_mount_rw();
1204

    
1205
	/* Create backup directory if needed */
1206
	safe_mkdir("{$g['cf_conf_path']}/backup");
1207

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

    
1229
	conf_mount_ro();
1230

    
1231
	return true;
1232
}
1233

    
1234
function set_device_perms() {
1235
	$devices = array(
1236
		'pf'	=> array(	'user'	=> 'proxy',
1237
					'group'	=> 'proxy',
1238
					'mode'	=> 0660),
1239
		);
1240

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

    
1251
?>
(11-11/48)