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['cf_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
	unlock($lockkey);
497

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

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

    
507
	return $config;
508
}
509

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

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

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

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

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

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

    
544
	return 0;
545
}
546

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

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

    
553
	conf_mount_rw();
554

    
555
	backup_config();
556

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

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

    
562
	unlock($lockkey);
563

    
564
	$config = parse_config(true);
565

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

    
568
	conf_mount_ro();
569

    
570
	return 0;
571
}
572

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

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

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

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

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

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

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

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

    
599
    return 0;
600
}
601

    
602
function config_validate($conffile) {
603

    
604
	global $g, $xmlerr;
605

    
606
	$xml_parser = xml_parser_create();
607

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

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

    
623
	fclose($fp);
624

    
625
	return true;
626
}
627

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

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

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

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

    
649
	$iflist = get_interface_list();
650

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

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

    
658
	echo <<<EOD
659

    
660
Valid interfaces are:
661

    
662

    
663
EOD;
664

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

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

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

    
686
Do you want to set up VLANs first? 
687

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

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

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

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

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

    
704
   !!! Auto Assigning Interfaces !!!
705

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

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

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

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

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

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

    
741
			echo <<<EOD
742

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

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

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

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

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

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

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

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

    
908
echo <<<EODD
909

    
910
You have chosen to remove the LAN interface.
911

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

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

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

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

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

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

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

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

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

    
995
		echo <<<EOD
996

    
997

    
998

    
999
EOD;
1000

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

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

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

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

    
1015
		echo " done!\n";
1016

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

    
1019
	}
1020
}
1021

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

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

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

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

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

    
1042
	return null;
1043
}
1044

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

    
1048
	$iflist = get_interface_list();
1049

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

    
1052
	echo <<<EOD
1053

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

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

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

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

    
1066
	$vlanif = 0;
1067

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

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

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

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

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

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

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

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

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

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

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

    
1208
	conf_mount_rw();
1209

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

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

    
1234
	conf_mount_ro();
1235

    
1236
	return true;
1237
}
1238

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

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

    
1256
?>
(11-11/51)