Project

General

Profile

Download (35.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
/****f* config/encrypted_configxml
47
 * NAME
48
 *   encrypted_configxml - Checks to see if config.xml is encrypted and if so, prompts to unlock.
49
 * INPUTS
50
 *   None
51
 * RESULT
52
 *   $config 	- rewrites config.xml without encryption
53
 ******/
54
function encrypted_configxml() {
55
	global $g, $config;
56
	if(file_exists($g['conf_path'] . "/config.xml")) {
57
		if($g['booting']) {
58
			$configtxt = file_get_contents($g['conf_path'] . "/config.xml");			
59
			if(tagfile_deformat($configtxt, $configtxt, "config.xml")) {
60
				$fp = fopen('php://stdin', 'r');
61
				$data = "";
62
				echo "\n\n*** Encrypted config.xml detected ***\n";
63
				while($data == "") {
64
					echo "\nEnter the password to decrypt config.xml: ";
65
					$decrypt_password = chop(fgets($fp));
66
					$data = decrypt_data($configtxt, $decrypt_password);
67
					if(!strstr($data, "<pfsense>"))
68
						$data = "";
69
					if($data) {
70
						$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
71
						fwrite($fd, $data);
72
						fclose($fd);
73
						exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
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
	return $config;
161
}
162

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

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

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

    
186
        return $last_backup;
187
}
188

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

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

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

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

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

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

    
267

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

    
276

    
277
EOD;
278
		}
279

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

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

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

    
298
	if (refcount_reference(1000) > 1)
299
		return;
300

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

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

    
323
/****f* config/conf_mount_ro
324
 * NAME
325
 *   conf_mount_ro - Mount filesystems readonly.
326
 * RESULT
327
 *   null
328
 ******/
329
function conf_mount_ro() {
330
	global $g;
331

    
332
	/* do not umount on cdrom or pfSense platforms */
333
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
334
		return;
335

    
336
	if (refcount_unreference(1000) > 0)
337
		return;
338

    
339
	clear_subsystem_dirty('mount');
340
	/* sync data, then force a remount of /cf */
341
	mwexec("/bin/sync; /bin/sync");
342
	mwexec("/sbin/mount -u -r -f {$g['cf_path']}");
343
	mwexec("/sbin/mount -u -r -f /");
344
}
345

    
346
/****f* config/convert_config
347
 * NAME
348
 *   convert_config - Attempt to update config.xml.
349
 * DESCRIPTION
350
 *   convert_config() reads the current global configuration
351
 *   and attempts to convert it to conform to the latest
352
 *   config.xml version. This allows major formatting changes
353
 *   to be made with a minimum of breakage.
354
 * RESULT
355
 *   null
356
 ******/
357
/* convert configuration, if necessary */
358
function convert_config() {
359
	global $config, $g;
360
	$now = date("H:i:s");
361
	log_error("Start Configuration upgrade at $now, set execution timeout to 15 minutes");
362
	//ini_set("max_execution_time", "900");
363

    
364
	/* special case upgrades */
365
	/* fix every minute crontab bogons entry */
366
	$cron_item_count = count($config['cron']['item']);
367
	for($x=0; $x<$cron_item_count; $x++) {
368
		if(stristr($config['cron']['item'][$x]['command'], "rc.update_bogons.sh")) {
369
			if($config['cron']['item'][$x]['hour'] == "*" ) {
370
		        $config['cron']['item'][$x]['hour'] = "3";
371
		 		write_config("Updated bogon update frequency to 3am");
372
		 		log_error("Updated bogon update frequency to 3am");
373
		 	}       
374
		}
375
	}
376
	if ($config['version'] == $g['latest_config'])
377
		return;		/* already at latest version */
378

    
379
	// Save off config version
380
	$prev_version = $config['version'];
381
	
382
	include_once('auth.inc');
383
	include_once('upgrade_config.inc');
384
	/* Loop and run upgrade_VER_to_VER() until we're at current version */
385
	while ($config['version'] < $g['latest_config']) {
386
		$cur = $config['version'] * 10;
387
		$next = $cur + 1;
388
		$migration_function = sprintf('upgrade_%03d_to_%03d', $cur, $next);
389
		$migration_function();
390
		$config['version'] = sprintf('%.1f', $next / 10);
391
		if($g['booting'])
392
			echo ".";
393
	}
394

    
395
	$now = date("H:i:s");
396
	log_error("Ended Configuration upgrade at $now");
397

    
398
	if ($prev_version != $config['version'])
399
		write_config("Upgraded config version level from {$prev_version} to {$config['version']}");
400

    
401
	if($g['booting'])
402
		echo "Loading new configuration...";
403
}
404

    
405
/****f* config/safe_write_file
406
 * NAME
407
 *   safe_write_file - Write a file out atomically
408
 * DESCRIPTION
409
 *   safe_write_file() Writes a file out atomically by first writing to a
410
 *   temporary file of the same name but ending with the pid of the current
411
 *   process, them renaming the temporary file over the original.
412
 * INPUTS
413
 *   $filename  - string containing the filename of the file to write
414
 *   $content   - string containing the file content to write to file
415
 *   $force_binary      - boolean denoting whether we should force binary
416
 *   mode writing.
417
 * RESULT
418
 *   boolean - true if successful, false if not
419
 ******/
420
function safe_write_file($file, $content, $force_binary) {
421
        $tmp_file = $file . "." . getmypid();
422
        $write_mode = $force_binary ? "wb" : "w";
423

    
424
        $fd = fopen($tmp_file, $write_mode);
425
        if (!$fd) {
426
                // Unable to open temporary file for writing
427
                return false;
428
        }
429
        if (!fwrite($fd, $content)) {
430
                // Unable to write to temporary file
431
                fclose($fd);
432
                return false;
433
        }
434
        fclose($fd);
435

    
436
        if (!rename($tmp_file, $file)) {
437
                // Unable to move temporary file to original
438
                unlink($tmp_file);
439
                return false;
440
        }
441
        return true;
442
}
443

    
444
/****f* config/write_config
445
 * NAME
446
 *   write_config - Backup and write the firewall configuration.
447
 * DESCRIPTION
448
 *   write_config() handles backing up the current configuration,
449
 *   applying changes, and regenerating the configuration cache.
450
 * INPUTS
451
 *   $desc	- string containing the a description of configuration changes
452
 *   $backup	- boolean: do not back up current configuration if false.
453
 * RESULT
454
 *   null
455
 ******/
456
/* save the system configuration */
457
function write_config($desc="Unknown", $backup = true) {
458
	global $config, $g;
459

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

    
463
	if($backup)
464
		backup_config();
465

    
466
	if (time() > mktime(0, 0, 0, 9, 1, 2004))       /* make sure the clock settings are plausible */
467
		$config['revision']['time'] = time();
468

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

    
473
	$config['revision']['description'] = "{$_SESSION['Username']}: " . $desc;
474
	$config['revision']['username'] = $_SESSION["Username"];
475

    
476
	conf_mount_rw();
477
	$lockkey = lock('config', LOCK_EX);
478

    
479
	/* generate configuration XML */
480
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
481

    
482
	/* write new configuration */
483
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
484
		log_error("WARNING: Config contents could not be save. Could not open file!");
485
		unlock($lockkey);
486
		file_notice("config.xml", "Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
487
		return -1;
488
	}
489
	
490
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
491
		cleanup_backupcache(5, true);
492
	} else {
493
		cleanup_backupcache(30, true);
494
	}
495

    
496
	/* re-read configuration */
497
	/* NOTE: We assume that the file can be parsed since we wrote it. */
498
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
499
	if ($config == -1) {
500
		$last_backup = discover_last_backup();
501
		if ($last_backup)
502
			restore_backup("/cf/conf/backup/{$last_backup}");
503
		else
504
			log_error(gettext("Could not restore config.xml."));
505
	} else
506
		generate_config_cache($config);
507

    
508
	unlock($lockkey);
509

    
510
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
511

    
512
	/* tell kernel to sync fs data */
513
	conf_mount_ro();
514

    
515
	/* sync carp entries to other firewalls */
516
	carp_sync_client();
517

    
518
	if(is_dir("/usr/local/pkg/write_config")) {
519
		/* process packager manager custom rules */
520
		run_plugins("/usr/local/pkg/write_config/");
521
	}
522

    
523
	return $config;
524
}
525

    
526
/****f* config/reset_factory_defaults
527
 * NAME
528
 *   reset_factory_defaults - Reset the system to its default configuration.
529
 * RESULT
530
 *   integer	- indicates completion
531
 ******/
532
function reset_factory_defaults($lock = false) {
533
	global $g;
534

    
535
	conf_mount_rw();
536
	if (!$lock)
537
		$lockkey = lock('config', LOCK_EX);
538

    
539
	/* create conf directory, if necessary */
540
	safe_mkdir("{$g['cf_conf_path']}");
541

    
542
	/* clear out /conf */
543
	$dh = opendir($g['conf_path']);
544
	while ($filename = readdir($dh)) {
545
		if (($filename != ".") && ($filename != "..")) {
546
			unlink_if_exists($g['conf_path'] . "/" . $filename);
547
		}
548
	}
549
	closedir($dh);
550

    
551
	/* copy default configuration */
552
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
553

    
554
	/* call the wizard */
555
	touch("/conf/trigger_initial_wizard");
556
	if (!$lock)
557
		unlock($lockkey);
558
	conf_mount_ro();
559

    
560
	return 0;
561
}
562

    
563
function config_restore($conffile) {
564
	global $config, $g;
565

    
566
	if (!file_exists($conffile))
567
		return 1;
568

    
569
	backup_config();
570

    
571
	conf_mount_rw();
572
	
573
	$lockkey = lock('config', LOCK_EX);
574

    
575
	unlink_if_exists("{$g['tmp_path']}/config.cache");
576
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
577

    
578
	unlock($lockkey);
579

    
580
	$config = parse_config(true);
581

    
582
	conf_mount_ro();
583

    
584
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
585

    
586
	return 0;
587
}
588

    
589
function config_install($conffile) {
590
	global $config, $g;
591

    
592
	if (!file_exists($conffile))
593
		return 1;
594

    
595
	if (!config_validate("{$conffile}"))
596
		return 1;
597

    
598
	if($g['booting'] == true)
599
		echo "Installing configuration...\n";
600
	else
601
		log_error("Installing configuration ....");
602

    
603
	conf_mount_rw();
604
	$lockkey = lock('config', LOCK_EX);
605

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

    
608
	/* unlink cache file if it exists */
609
	if(file_exists("{$g['tmp_path']}/config.cache"))
610
		unlink("{$g['tmp_path']}/config.cache");
611

    
612
	unlock($lockkey);
613
	conf_mount_ro();
614

    
615
    return 0;
616
}
617

    
618
function config_validate($conffile) {
619

    
620
	global $g, $xmlerr;
621

    
622
	$xml_parser = xml_parser_create();
623

    
624
	if (!($fp = fopen($conffile, "r"))) {
625
		$xmlerr = "XML error: unable to open file";
626
		return false;
627
	}
628

    
629
	while ($data = fread($fp, 4096)) {
630
		if (!xml_parse($xml_parser, $data, feof($fp))) {
631
			$xmlerr = sprintf("%s at line %d",
632
						xml_error_string(xml_get_error_code($xml_parser)),
633
						xml_get_current_line_number($xml_parser));
634
			return false;
635
		}
636
	}
637
	xml_parser_free($xml_parser);
638

    
639
	fclose($fp);
640

    
641
	return true;
642
}
643

    
644
function set_networking_interfaces_ports() {
645
	global $noreboot;
646
	global $config;
647
	global $g;
648
	global $fp;
649

    
650
	$fp = fopen('php://stdin', 'r');
651

    
652
	$memory = get_memory();
653
	$avail = $memory[0];
654

    
655
	if($avail < $g['minimum_ram_warning']) {
656
		echo "\n\n\n";
657
		echo "DANGER!  WARNING!  ACHTUNG!\n\n";
658
		echo "{$g['product_name']} requires *AT LEAST* {$g['minimum_ram_warning_text']} RAM to function correctly.\n";
659
		echo "Only ({$avail}) MB RAM has been detected.\n";
660
		echo "\nPress ENTER to continue. ";
661
		fgets($fp);
662
		echo "\n";
663
	}
664

    
665
	$iflist = get_interface_list();
666

    
667
/* Function flow is based on $key and $auto_assign or the lack thereof */	
668
	$key = null;
669

    
670
/* Only present auto interface option if running from LiveCD and interface mismatch*/
671
	if ((ereg("cdrom", $g['platform'])) && is_interface_mismatch())
672
		$auto_assign = false;
673

    
674
	echo <<<EOD
675

    
676
Valid interfaces are:
677

    
678

    
679
EOD;
680

    
681
	if(!is_array($iflist)) {
682
		echo "No interfaces found!\n";
683
		$iflist = array();
684
	} else {
685
		foreach ($iflist as $iface => $ifa) {
686
			echo sprintf("% -6s%s%s\t%s\n", $iface, $ifa['mac'],
687
				$ifa['up'] ? "   (up)" : "   (down)", $ifa['dmesg']);
688
		}
689
	}
690

    
691
	if ($auto_assign) {
692
		echo <<<EOD
693
		
694
		!!! LiveCD Detected: Auto Interface Option !!!!
695
BEGIN MANUAL CONFIGURATION OR WE WILL PROCEED WITH AUTO CONFIGURATION.
696

    
697
EOD;
698
	}	
699
	
700
	echo <<<EOD
701

    
702
Do you want to set up VLANs first? 
703

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

    
707
Do you want to set up VLANs now [y|n]? 
708
EOD;
709

    
710
	if ($auto_assign) {
711
		$key = timeout();
712

    
713
	} else
714
		$key = chop(fgets($fp));
715

    
716
	if (!isset($key) and $auto_assign) {	// Auto Assign Interfaces
717
		do {
718
			echo <<<EOD
719

    
720
   !!! Auto Assigning Interfaces !!!
721

    
722
For installation purposes, you must plug in at least one NIC
723
for the LAN connection. If you plug in a second NIC it will be
724
assigned to WAN. Otherwise, we'll temporarily assign WAN to the
725
next available NIC found regardless of activity. You should
726
assign and configure the WAN interface according to your requirements
727

    
728
If you haven't plugged in any network cables yet,
729
now is the time to do so.
730
We'll keep trying until you do.
731

    
732
Searching for active interfaces...
733
 
734
EOD;
735
			unset($wanif, $lanif);
736

    
737
			$media_iflist = $plugged_in = array();
738
			$media_iflist = get_interface_list("media");
739
			foreach ($media_iflist as $iface => $ifa) {
740
				if ($ifa['up']) 
741
					$plugged_in[] = $iface;
742
				
743
			}
744

    
745
			$lanif = array_shift($plugged_in);
746
			$wanif = array_shift($plugged_in);
747

    
748
			if(isset($lanif) && !isset($wanif)) {
749
				foreach ($iflist as $iface => $ifa) {
750
					if ($iface != $lanif) {
751
						$wanif = $iface;
752
						break;
753
					}
754
				}
755
			}
756

    
757
			echo <<<EOD
758

    
759
Assigned WAN to : $wanif 
760
Assigned LAN to : $lanif
761

    
762
If you don't like this assignment,
763
press any key to go back to manual configuration. 
764

    
765
EOD;
766
			$key = timeout(20);
767
			if(isset($key))
768
				return;
769
		} while (!isset($wanif));
770

    
771
		$config['system']['enablesshd'] = 'enabled';	
772
		$key = 'y';
773

    
774
	} else {		//Manually assign interfaces	
775
		if (in_array($key, array('y', 'Y')))
776
			vlan_setup();
777
	
778
		if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
779
	
780
			echo "\n\nVLAN interfaces:\n\n";
781
			foreach ($config['vlans']['vlan'] as $vlan) {
782
	
783
				echo sprintf("% -16s%s\n", "{$vlan['if']}_vlan{$vlan['tag']}",
784
					"VLAN tag {$vlan['tag']}, parent interface {$vlan['if']}");
785
	
786
				$iflist[$vlan['if'] . '_vlan' . $vlan['tag']] = array();
787
			}
788
		}
789
	
790
		echo <<<EOD
791
	
792
*NOTE*  {$g['product_name']} requires {$g['minimum_nic_count_text']} assigned interfaces to function.
793
        If you do not have {$g['minimum_nic_count_text']} interfaces you CANNOT continue. 
794

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

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

    
919
	if (in_array($key, array('y', 'Y'))) {
920
		if($lanif) {
921
			$config['interfaces']['lan']['if'] = $lanif;
922
			$config['interfaces']['lan']['enable'] = true;
923
		} elseif (!$g['booting'] && !$auto_assign) {
924

    
925
echo <<<EODD
926

    
927
You have chosen to remove the LAN interface.
928

    
929
Would you like to remove the LAN IP address and
930
unload the interface now? [y|n]? 
931
EODD;
932

    
933
				if (strcasecmp(chop(fgets($fp)), "y") == 0) {
934
					if($config['interfaces']['lan']['if'])
935
						mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
936
				}
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
		} else {
952
			if(isset($config['interfaces']['lan']['if']))
953
				mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
954
			if(isset($config['interfaces']['lan']))
955
				unset($config['interfaces']['lan']);
956
			if(isset($config['dhcpd']['lan']))
957
				unset($config['dhcpd']['lan']);
958
			if(isset($config['interfaces']['lan']['if']))
959
				unset($config['interfaces']['lan']['if']);
960
			if(isset($config['interfaces']['wan']['blockpriv']))
961
				unset($config['interfaces']['wan']['blockpriv']);
962
			if(isset($config['shaper']))
963
				unset($config['shaper']);
964
			if(isset($config['ezshaper']))
965
				unset($config['ezshaper']);
966
			if(isset($config['nat']))
967
				unset($config['nat']);				
968
		}
969
		if (preg_match($g['wireless_regex'], $lanif)) {
970
			if (is_array($config['interfaces']['lan']) &&
971
				(!is_array($config['interfaces']['lan']['wireless'])))
972
				$config['interfaces']['lan']['wireless'] = array();
973
		} else {
974
			unset($config['interfaces']['lan']['wireless']);
975
		}
976

    
977
		$config['interfaces']['wan']['if'] = $wanif;
978
		$config['interfaces']['wan']['enable'] = true;
979
		if (preg_match($g['wireless_regex'], $wanif)) {
980
			if (is_array($config['interfaces']['lan']) &&
981
				(!is_array($config['interfaces']['wan']['wireless'])))
982
				$config['interfaces']['wan']['wireless'] = array();
983
		} else {
984
			unset($config['interfaces']['wan']['wireless']);
985
		}
986

    
987
		for ($i = 0; $i < count($optif); $i++) {
988
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
989
				$config['interfaces']['opt' . ($i+1)] = array();
990

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

    
993
			/* wireless interface? */
994
			if (preg_match($g['wireless_regex'], $optif[$i])) {
995
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
996
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
997
			} else {
998
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
999
			}
1000

    
1001
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1002
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1003
		}
1004

    
1005
		/* remove all other (old) optional interfaces */
1006
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1007
			unset($config['interfaces']['opt' . ($i+1)]);
1008

    
1009
		echo "\nWriting configuration...";
1010
		write_config();
1011
		echo "done.\n";
1012

    
1013
		echo <<<EOD
1014

    
1015

    
1016

    
1017
EOD;
1018

    
1019
		fclose($fp);
1020
		if($g['booting'])
1021
			return;
1022

    
1023
		echo "One moment while we reload the settings...";
1024

    
1025
		$g['booting'] = false;
1026

    
1027
		/* XXX: ermal - disable it for now this is used during bootup at best so shouldn't be needed.
1028
		 * 		For now just comment it out and later remove it completely.
1029
		 * resync everything 
1030
			reload_all_sync();
1031
		 */
1032

    
1033
		echo " done!\n";
1034

    
1035
		touch("{$g['tmp_path']}/assign_complete");
1036

    
1037
	}
1038
}
1039

    
1040
function autodetect_interface($ifname, $fp) {
1041
	$iflist_prev = get_interface_list("media");
1042
	echo <<<EOD
1043

    
1044
Connect the {$ifname} interface now and make sure that the link is up.
1045
Then press ENTER to continue.
1046

    
1047
EOD;
1048
	fgets($fp);
1049
	$iflist = get_interface_list("media");
1050

    
1051
	foreach ($iflist_prev as $ifn => $ifa) {
1052
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1053
			echo "Detected link-up on interface {$ifn}.\n";
1054
			return $ifn;
1055
		}
1056
	}
1057

    
1058
	echo "No link-up detected.\n";
1059

    
1060
	return null;
1061
}
1062

    
1063
function vlan_setup() {
1064
	global $iflist, $config, $g, $fp;
1065

    
1066
	$iflist = get_interface_list();
1067

    
1068
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1069

    
1070
	echo <<<EOD
1071

    
1072
WARNING: all existing VLANs will be cleared if you proceed!
1073

    
1074
Do you want to proceed [y|n]?
1075
EOD;
1076

    
1077
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1078
		return;
1079
	}
1080

    
1081
	$config['vlans']['vlan'] = array();
1082
	echo "\n";
1083

    
1084
	$vlanif = 0;
1085

    
1086
	while (1) {
1087
		$vlan = array();
1088

    
1089
		echo "\n\nVLAN Capable interfaces:\n\n";
1090
		if(!is_array($iflist)) {
1091
			echo "No interfaces found!\n";
1092
		} else {
1093
			$vlan_capable=0;
1094
			foreach ($iflist as $iface => $ifa) {
1095
				if (is_jumbo_capable($iface)) {
1096
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1097
						$ifa['up'] ? "   (up)" : "");
1098
					$vlan_capable++;
1099
				}
1100
			}
1101
		}
1102

    
1103
		if($vlan_capable == 0) {
1104
			echo "No VLAN capable interfaces detected.\n";
1105
			return;
1106
		}
1107

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

    
1111
		if ($vlan['if']) {
1112
			if (!array_key_exists($vlan['if'], $iflist) or
1113
			    !is_jumbo_capable($vlan['if'])) {
1114
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1115
				continue;
1116
			}
1117
		} else {
1118
			break;
1119
		}
1120

    
1121
		echo "Enter the VLAN tag (1-4094): ";
1122
		$vlan['tag'] = chop(fgets($fp));
1123
		$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
1124
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1125
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1126
			continue;
1127
		}
1128
		
1129
		$config['vlans']['vlan'][] = $vlan;
1130
		$vlanif++;
1131
	}
1132
}
1133

    
1134
function cleanup_backupcache($revisions = 30, $lock = false) {
1135
	global $g;
1136
	$i = false;
1137
	
1138
	if (!$lock)
1139
		$lockkey = lock('config');
1140

    
1141
	conf_mount_rw();
1142

    
1143
	$backups = get_backups();
1144
	if ($backups) {
1145
		$baktimes = $backups['versions'];
1146
		unset($backups['versions']);
1147
	} else {
1148
		$backups = array();
1149
		$baktimes = array();
1150
	}
1151
	$newbaks = array();
1152
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1153
	$tocache = array();
1154

    
1155
	foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1156
		if(filesize($backup) == 0) {
1157
			unlink($backup);
1158
			continue;
1159
		}
1160
		$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1161
		if(!in_array($tocheck, $baktimes)) {
1162
			$i = true;
1163
			if($g['booting'])
1164
				echo ".";
1165
			$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1166
			if($newxml == "-1") {
1167
				log_error("The backup cache file $backup is corrupted.  Unlinking.");
1168
				unlink($backup);
1169
				log_error("The backup cache file $backup is corrupted.  Unlinking.");
1170
				continue;
1171
			}
1172
			if($newxml['revision']['description'] == "")
1173
				$newxml['revision']['description'] = "Unknown";
1174
			$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1175
		}
1176
	}
1177
	foreach($backups as $checkbak) {
1178
		if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1179
			$newbaks[] = $checkbak;
1180
		} else {
1181
			$i = true;
1182
			if($g['booting']) print " " . $tocheck . "r";
1183
		}
1184
	}
1185
	foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1186
	if(is_int($revisions) and (count($tocache) > $revisions)) {
1187
		$toslice = array_slice(array_keys($tocache), 0, $revisions);
1188
		foreach($toslice as $sliced)
1189
			$newcache[$sliced] = $tocache[$sliced];
1190
		foreach($tocache as $version => $versioninfo) {
1191
			if(!in_array($version, array_keys($newcache))) {
1192
				unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1193
				if($g['booting']) print " " . $tocheck . "d";
1194
			}
1195
		}
1196
		$tocache = $newcache;
1197
	}
1198
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1199
	fwrite($bakout, serialize($tocache));
1200
	fclose($bakout);
1201
	conf_mount_ro();
1202

    
1203
	if($g['booting'] && $i)
1204
		print "done.\n";
1205
	if (!$lock)
1206
		unlock($lockkey);
1207
}
1208

    
1209
function get_backups() {
1210
	global $g;
1211
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1212
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1213
		$bakvers = array_keys($confvers);
1214
		$toreturn = array();
1215
		sort($bakvers);
1216
		// 	$bakvers = array_reverse($bakvers);
1217
		foreach(array_reverse($bakvers) as $bakver)
1218
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1219
	} else {
1220
		return false;
1221
	}
1222
	$toreturn['versions'] = $bakvers;
1223
	return $toreturn;
1224
}
1225

    
1226
function backup_config() {
1227
	global $config, $g;
1228

    
1229
	if($g['platform'] == "cdrom")
1230
		return;
1231

    
1232
	conf_mount_rw();
1233

    
1234
	/* Create backup directory if needed */
1235
	safe_mkdir("{$g['cf_conf_path']}/backup");
1236

    
1237
    if($config['revision']['time'] == "") {
1238
            $baktime = 0;
1239
    } else {
1240
            $baktime = $config['revision']['time'];
1241
    }
1242
    if($config['revision']['description'] == "") {
1243
            $bakdesc = "Unknown";
1244
    } else {
1245
            $bakdesc = $config['revision']['description'];
1246
    }
1247
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1248
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1249
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1250
    } else {
1251
            $backupcache = array();
1252
    }
1253
    $backupcache[$baktime] = array('description' => $bakdesc);
1254
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1255
    fwrite($bakout, serialize($backupcache));
1256
    fclose($bakout);
1257

    
1258
	conf_mount_ro();
1259

    
1260
	return true;
1261
}
1262

    
1263
function set_device_perms() {
1264
	$devices = array(
1265
		'pf'	=> array(	'user'	=> 'root',
1266
					'group'	=> 'proxy',
1267
					'mode'	=> 0660),
1268
		);
1269

    
1270
	foreach ($devices as $name => $attr) {
1271
		$path = "/dev/$name";
1272
		if (file_exists($path)) {
1273
			chown($path, $attr['user']);
1274
			chgrp($path, $attr['group']);
1275
			chmod($path, $attr['mode']);
1276
		}
1277
	}
1278
}
1279

    
1280
?>
(11-11/50)