Project

General

Profile

Download (35.6 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
$config_parsed = false;
47

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

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

    
162
	return $config;
163
}
164

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

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

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

    
188
        return $last_backup;
189
}
190

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

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

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

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

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

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

    
269

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

    
278

    
279
EOD;
280
		}
281

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

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

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

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

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

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

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

    
340
	/* do not umount on cdrom or pfSense platforms */
341
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
342
		return;
343

    
344
	/* firmare upgrade in progress */
345
	if (is_subsystem_dirty('firmwarelock'))
346
		return;
347

    
348
	/* do not umount if generating ssh keys */
349
	if (is_subsystem_dirty('sshdkeys'))
350
		return;
351

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

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

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

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

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

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

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

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

    
422
/****f* config/safe_write_file
423
 * NAME
424
 *   safe_write_file - Write a file out atomically
425
 * DESCRIPTION
426
 *   safe_write_file() Writes a file out atomically by first writing to a
427
 *   temporary file of the same name but ending with the pid of the current
428
 *   process, them renaming the temporary file over the original.
429
 * INPUTS
430
 *   $filename  - string containing the filename of the file to write
431
 *   $content   - string containing the file content to write to file
432
 *   $force_binary      - boolean denoting whether we should force binary
433
 *   mode writing.
434
 * RESULT
435
 *   boolean - true if successful, false if not
436
 ******/
437
function safe_write_file($file, $content, $force_binary) {
438
        $tmp_file = $file . "." . getmypid();
439
        $write_mode = $force_binary ? "wb" : "w";
440

    
441
        $fd = fopen($tmp_file, $write_mode);
442
        if (!$fd) {
443
                // Unable to open temporary file for writing
444
                return false;
445
        }
446
        if (!fwrite($fd, $content)) {
447
                // Unable to write to temporary file
448
                fclose($fd);
449
                return false;
450
        }
451
        fclose($fd);
452

    
453
        if (!rename($tmp_file, $file)) {
454
                // Unable to move temporary file to original
455
                unlink($tmp_file);
456
                return false;
457
        }
458
        return true;
459
}
460

    
461
/****f* config/write_config
462
 * NAME
463
 *   write_config - Backup and write the firewall configuration.
464
 * DESCRIPTION
465
 *   write_config() handles backing up the current configuration,
466
 *   applying changes, and regenerating the configuration cache.
467
 * INPUTS
468
 *   $desc	- string containing the a description of configuration changes
469
 *   $backup	- boolean: do not back up current configuration if false.
470
 * RESULT
471
 *   null
472
 ******/
473
/* save the system configuration */
474
function write_config($desc="Unknown", $backup = true) {
475
	global $config, $g;
476

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

    
480
	if($backup)
481
		backup_config();
482

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

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

    
490
	$config['revision']['description'] = $desc;
491
	$config['revision']['time'] = $changetime;
492

    
493
	$lockkey = lock('config');
494

    
495
	/* generate configuration XML */
496
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
497

    
498
	conf_mount_rw();
499

    
500
	/* write new configuration */
501
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
502
		log_error("WARNING: Config contents could not be save. Could not open file!");
503
		unlock($lockkey);
504
		die("Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
505
	}
506
	
507
	if($g['platform'] == "embedded" or $g['platform'] == "nanobsd") {
508
		cleanup_backupcache(5, true);
509
	} else {
510
		cleanup_backupcache(30, true);
511
	}
512

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

    
516
	/* write config cache */
517
	$fd = @fopen("{$g['tmp_path']}/config.cache", "wb");
518
	if ($fd) {
519
		fwrite($fd, serialize($config));
520
		fclose($fd);
521
	}
522

    
523
	/* tell kernel to sync fs data */
524
	if (!$g['booting'])
525
		conf_mount_ro();
526

    
527
	unlock($lockkey);
528

    
529
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
530

    
531
	/* sync carp entries to other firewalls */
532
	carp_sync_client();
533

    
534
	if(is_dir("/usr/local/pkg/write_config")) {
535
		/* process packager manager custom rules */
536
		run_plugins("/usr/local/pkg/write_config/");
537
	}
538

    
539
	return $config;
540
}
541

    
542
/****f* config/reset_factory_defaults
543
 * NAME
544
 *   reset_factory_defaults - Reset the system to its default configuration.
545
 * RESULT
546
 *   integer	- indicates completion
547
 ******/
548
function reset_factory_defaults($lock = false) {
549
	global $g;
550

    
551
	if (!$lock)
552
		$lockkey = lock('config');
553
	conf_mount_rw();
554

    
555
	/* create conf directory, if necessary */
556
	safe_mkdir("{$g['cf_conf_path']}");
557

    
558
	/* clear out /conf */
559
	$dh = opendir($g['conf_path']);
560
	while ($filename = readdir($dh)) {
561
		if (($filename != ".") && ($filename != "..")) {
562
			unlink_if_exists($g['conf_path'] . "/" . $filename);
563
		}
564
	}
565
	closedir($dh);
566

    
567
	/* copy default configuration */
568
	copy("{$g['conf_default_path']}/config.xml", "{$g['conf_path']}/config.xml");
569

    
570
	/* call the wizard */
571
	touch("/conf/trigger_initial_wizard");
572
	conf_mount_ro();
573
	if (!$lock)
574
		unlock($lockkey);
575

    
576
	return 0;
577
}
578

    
579
function config_restore($conffile) {
580
	global $config, $g;
581

    
582
	if (!file_exists($conffile))
583
		return 1;
584

    
585
	conf_mount_rw();
586

    
587
	backup_config();
588

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

    
591
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
592
	unlink_if_exists("{$g['tmp_path']}/config.cache");
593

    
594
	unlock($lockkey);
595

    
596
	$config = parse_config(true);
597

    
598
	conf_mount_ro();
599

    
600
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
601

    
602
	return 0;
603
}
604

    
605
function config_install($conffile) {
606
	global $config, $g;
607

    
608
	if (!file_exists($conffile))
609
		return 1;
610

    
611
	if (!config_validate("{$conffile}"))
612
		return 1;
613

    
614
	if($g['booting'] == true)
615
		echo "Installing configuration...\n";
616
	else
617
		log_error("Installing configuration ....");
618

    
619
	conf_mount_rw();
620
	$lockkey = lock('config');
621

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

    
624
	/* unlink cache file if it exists */
625
	if(file_exists("{$g['tmp_path']}/config.cache"))
626
		unlink("{$g['tmp_path']}/config.cache");
627

    
628
	unlock($lockkey);
629
	conf_mount_ro();
630

    
631
    return 0;
632
}
633

    
634
function config_validate($conffile) {
635

    
636
	global $g, $xmlerr;
637

    
638
	$xml_parser = xml_parser_create();
639

    
640
	if (!($fp = fopen($conffile, "r"))) {
641
		$xmlerr = "XML error: unable to open file";
642
		return false;
643
	}
644

    
645
	while ($data = fread($fp, 4096)) {
646
		if (!xml_parse($xml_parser, $data, feof($fp))) {
647
			$xmlerr = sprintf("%s at line %d",
648
						xml_error_string(xml_get_error_code($xml_parser)),
649
						xml_get_current_line_number($xml_parser));
650
			return false;
651
		}
652
	}
653
	xml_parser_free($xml_parser);
654

    
655
	fclose($fp);
656

    
657
	return true;
658
}
659

    
660
function set_networking_interfaces_ports() {
661
	global $noreboot;
662
	global $config;
663
	global $g;
664
	global $fp;
665

    
666
	$fp = fopen('php://stdin', 'r');
667

    
668
	$memory = get_memory();
669
	$avail = $memory[0];
670

    
671
	if($avail < $g['minimum_ram_warning']) {
672
		echo "\n\n\n";
673
		echo "DANGER!  WARNING!  ACHTUNG!\n\n";
674
		echo "{$g['product_name']} requires *AT LEAST* {$g['minimum_ram_warning_text']} RAM to function correctly.\n";
675
		echo "Only ({$avail}) MB RAM has been detected.\n";
676
		echo "\nPress ENTER to continue. ";
677
		fgets($fp);
678
		echo "\n";
679
	}
680

    
681
	$iflist = get_interface_list();
682

    
683
/* Function flow is based on $key and $auto_assign or the lack thereof */	
684
	$key = null;
685

    
686
/* Only present auto interface option if running from LiveCD and interface mismatch*/
687
	if ((ereg("cdrom", $g['platform'])) && is_interface_mismatch())
688
		$auto_assign = false;
689

    
690
	echo <<<EOD
691

    
692
Valid interfaces are:
693

    
694

    
695
EOD;
696

    
697
	if(!is_array($iflist)) {
698
		echo "No interfaces found!\n";
699
		$iflist = array();
700
	} else {
701
		foreach ($iflist as $iface => $ifa) {
702
			echo sprintf("% -6s%s%s\t%s\n", $iface, $ifa['mac'],
703
				$ifa['up'] ? "   (up)" : "   (down)", $ifa['dmesg']);
704
		}
705
	}
706

    
707
	if ($auto_assign) {
708
		echo <<<EOD
709
		
710
		!!! LiveCD Detected: Auto Interface Option !!!!
711
BEGIN MANUAL CONFIGURATION OR WE WILL PROCEED WITH AUTO CONFIGURATION.
712

    
713
EOD;
714
	}	
715
	
716
	echo <<<EOD
717

    
718
Do you want to set up VLANs first? 
719

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

    
723
Do you want to set up VLANs now [y|n]? 
724
EOD;
725

    
726
	if ($auto_assign) {
727
		$key = timeout();
728

    
729
	} else
730
		$key = chop(fgets($fp));
731

    
732
	if (!isset($key) and $auto_assign) {	// Auto Assign Interfaces
733
		do {
734
			echo <<<EOD
735

    
736
   !!! Auto Assigning Interfaces !!!
737

    
738
For installation purposes, you must plug in at least one NIC
739
for the LAN connection. If you plug in a second NIC it will be
740
assigned to WAN. Otherwise, we'll temporarily assign WAN to the
741
next available NIC found regardless of activity. You should
742
assign and configure the WAN interface according to your requirements
743

    
744
If you haven't plugged in any network cables yet,
745
now is the time to do so.
746
We'll keep trying until you do.
747

    
748
Searching for active interfaces...
749
 
750
EOD;
751
			unset($wanif, $lanif);
752

    
753
			$media_iflist = $plugged_in = array();
754
			$media_iflist = get_interface_list("media");
755
			foreach ($media_iflist as $iface => $ifa) {
756
				if ($ifa['up']) 
757
					$plugged_in[] = $iface;
758
				
759
			}
760

    
761
			$lanif = array_shift($plugged_in);
762
			$wanif = array_shift($plugged_in);
763

    
764
			if(isset($lanif) && !isset($wanif)) {
765
				foreach ($iflist as $iface => $ifa) {
766
					if ($iface != $lanif) {
767
						$wanif = $iface;
768
						break;
769
					}
770
				}
771
			}
772

    
773
			echo <<<EOD
774

    
775
Assigned WAN to : $wanif 
776
Assigned LAN to : $lanif
777

    
778
If you don't like this assignment,
779
press any key to go back to manual configuration. 
780

    
781
EOD;
782
			$key = timeout(20);
783
			if(isset($key))
784
				return;
785
		} while (!isset($wanif));
786

    
787
		$config['system']['enablesshd'] = 'enabled';	
788
		$key = 'y';
789

    
790
	} else {		//Manually assign interfaces	
791
		if (in_array($key, array('y', 'Y')))
792
			vlan_setup();
793
	
794
		if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
795
	
796
			echo "\n\nVLAN interfaces:\n\n";
797
			foreach ($config['vlans']['vlan'] as $vlan) {
798
	
799
				echo sprintf("% -16s%s\n", "{$vlan['if']}_vlan{$vlan['tag']}",
800
					"VLAN tag {$vlan['tag']}, parent interface {$vlan['if']}");
801
	
802
				$iflist[$vlan['if'] . '_vlan' . $vlan['tag']] = array();
803
			}
804
		}
805
	
806
		echo <<<EOD
807
	
808
*NOTE*  {$g['product_name']} requires {$g['minimum_nic_count_text']} assigned interfaces to function.
809
        If you do not have {$g['minimum_nic_count_text']} interfaces you CANNOT continue. 
810

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

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

    
935
	if (in_array($key, array('y', 'Y'))) {
936
		if($lanif) {
937
			$config['interfaces']['lan']['if'] = $lanif;
938
		} elseif (!$g['booting'] && !$auto_assign) {
939

    
940
echo <<<EODD
941

    
942
You have chosen to remove the LAN interface.
943

    
944
Would you like to remove the LAN IP address and
945
unload the interface now? [y|n]? 
946
EODD;
947

    
948
				if (strcasecmp(chop(fgets($fp)), "y") == 0) {
949
					if($config['interfaces']['lan']['if'])
950
						mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
951
				}
952
				if(isset($config['interfaces']['lan']))
953
					unset($config['interfaces']['lan']);
954
				if(isset($config['dhcpd']['lan']))
955
					unset($config['dhcpd']['lan']);
956
				if(isset($config['interfaces']['lan']['if']))
957
					unset($config['interfaces']['lan']['if']);
958
				if(isset($config['interfaces']['wan']['blockpriv']))
959
					unset($config['interfaces']['wan']['blockpriv']);
960
				if(isset($config['shaper']))
961
					unset($config['shaper']);
962
				if(isset($config['ezshaper']))
963
					unset($config['ezshaper']);
964
				if(isset($config['nat']))
965
					unset($config['nat']);				
966
		} else {
967
			if(isset($config['interfaces']['lan']['if']))
968
				mwexec("/sbin/ifconfig delete " . $config['interfaces']['lan']['if']);
969
			if(isset($config['interfaces']['lan']))
970
				unset($config['interfaces']['lan']);
971
			if(isset($config['dhcpd']['lan']))
972
				unset($config['dhcpd']['lan']);
973
			if(isset($config['interfaces']['lan']['if']))
974
				unset($config['interfaces']['lan']['if']);
975
			if(isset($config['interfaces']['wan']['blockpriv']))
976
				unset($config['interfaces']['wan']['blockpriv']);
977
			if(isset($config['shaper']))
978
				unset($config['shaper']);
979
			if(isset($config['ezshaper']))
980
				unset($config['ezshaper']);
981
			if(isset($config['nat']))
982
				unset($config['nat']);				
983
		}
984
		if (preg_match($g['wireless_regex'], $lanif)) {
985
			if (is_array($config['interfaces']['lan']) &&
986
				(!is_array($config['interfaces']['lan']['wireless'])))
987
				$config['interfaces']['lan']['wireless'] = array();
988
		} else {
989
			unset($config['interfaces']['lan']['wireless']);
990
		}
991

    
992
		$config['interfaces']['wan']['if'] = $wanif;
993
		if (preg_match($g['wireless_regex'], $wanif)) {
994
			if (is_array($config['interfaces']['lan']) &&
995
				(!is_array($config['interfaces']['wan']['wireless'])))
996
				$config['interfaces']['wan']['wireless'] = array();
997
		} else {
998
			unset($config['interfaces']['wan']['wireless']);
999
		}
1000

    
1001
		for ($i = 0; $i < count($optif); $i++) {
1002
			if (!is_array($config['interfaces']['opt' . ($i+1)]))
1003
				$config['interfaces']['opt' . ($i+1)] = array();
1004

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

    
1007
			/* wireless interface? */
1008
			if (preg_match($g['wireless_regex'], $optif[$i])) {
1009
				if (!is_array($config['interfaces']['opt' . ($i+1)]['wireless']))
1010
					$config['interfaces']['opt' . ($i+1)]['wireless'] = array();
1011
			} else {
1012
				unset($config['interfaces']['opt' . ($i+1)]['wireless']);
1013
			}
1014

    
1015
			unset($config['interfaces']['opt' . ($i+1)]['enable']);
1016
			$config['interfaces']['opt' . ($i+1)]['descr'] = "OPT" . ($i+1);
1017
		}
1018

    
1019
		/* remove all other (old) optional interfaces */
1020
		for (; isset($config['interfaces']['opt' . ($i+1)]); $i++)
1021
			unset($config['interfaces']['opt' . ($i+1)]);
1022

    
1023
		echo "\nWriting configuration...";
1024
		write_config();
1025
		echo "done.\n";
1026

    
1027
		echo <<<EOD
1028

    
1029

    
1030

    
1031
EOD;
1032

    
1033
		fclose($fp);
1034
		if($g['booting'])
1035
			return;
1036

    
1037
		echo "One moment while we reload the settings...";
1038

    
1039
		$g['booting'] = false;
1040

    
1041
		/* XXX: ermal - disable it for now this is used during bootup at best so shouldn't be needed.
1042
		 * 		For now just comment it out and later remove it completely.
1043
		 * resync everything 
1044
			reload_all_sync();
1045
		 */
1046

    
1047
		echo " done!\n";
1048

    
1049
		touch("{$g['tmp_path']}/assign_complete");
1050

    
1051
	}
1052
}
1053

    
1054
function autodetect_interface($ifname, $fp) {
1055
	$iflist_prev = get_interface_list("media");
1056
	echo <<<EOD
1057

    
1058
Connect the {$ifname} interface now and make sure that the link is up.
1059
Then press ENTER to continue.
1060

    
1061
EOD;
1062
	fgets($fp);
1063
	$iflist = get_interface_list("media");
1064

    
1065
	foreach ($iflist_prev as $ifn => $ifa) {
1066
		if (!$ifa['up'] && $iflist[$ifn]['up']) {
1067
			echo "Detected link-up on interface {$ifn}.\n";
1068
			return $ifn;
1069
		}
1070
	}
1071

    
1072
	echo "No link-up detected.\n";
1073

    
1074
	return null;
1075
}
1076

    
1077
function vlan_setup() {
1078
	global $iflist, $config, $g, $fp;
1079

    
1080
	$iflist = get_interface_list();
1081

    
1082
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
1083

    
1084
	echo <<<EOD
1085

    
1086
WARNING: all existing VLANs will be cleared if you proceed!
1087

    
1088
Do you want to proceed [y|n]?
1089
EOD;
1090

    
1091
	if (strcasecmp(chop(fgets($fp)), "y") != 0)
1092
		return;
1093
	}
1094

    
1095
	$config['vlans']['vlan'] = array();
1096
	echo "\n";
1097

    
1098
	$vlanif = 0;
1099

    
1100
	while (1) {
1101
		$vlan = array();
1102

    
1103
		echo "\n\nVLAN Capable interfaces:\n\n";
1104
		if(!is_array($iflist)) {
1105
			echo "No interfaces found!\n";
1106
		} else {
1107
			$vlan_capable=0;
1108
			foreach ($iflist as $iface => $ifa) {
1109
				if (is_jumbo_capable($iface)) {
1110
					echo sprintf("% -8s%s%s\n", $iface, $ifa['mac'],
1111
						$ifa['up'] ? "   (up)" : "");
1112
					$vlan_capable++;
1113
				}
1114
			}
1115
		}
1116

    
1117
		if($vlan_capable == 0) {
1118
			echo "No VLAN capable interfaces detected.\n";
1119
			return;
1120
		}
1121

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

    
1125
		if ($vlan['if']) {
1126
			if (!array_key_exists($vlan['if'], $iflist) or
1127
			    !is_jumbo_capable($vlan['if'])) {
1128
				echo "\nInvalid interface name '{$vlan['if']}'\n";
1129
				continue;
1130
			}
1131
		} else {
1132
			break;
1133
		}
1134

    
1135
		echo "Enter the VLAN tag (1-4094): ";
1136
		$vlan['tag'] = chop(fgets($fp));
1137
		$vlan['vlanif'] = "{$vlan['if']}_vlan{$vlan['tag']}";
1138
		if (!is_numericint($vlan['tag']) || ($vlan['tag'] < 1) || ($vlan['tag'] > 4094)) {
1139
			echo "\nInvalid VLAN tag '{$vlan['tag']}'\n";
1140
			continue;
1141
		}
1142
		
1143
		$config['vlans']['vlan'][] = $vlan;
1144
		$vlanif++;
1145
	}
1146
}
1147

    
1148
function cleanup_backupcache($revisions = 30, $lock = false) {
1149
	global $g;
1150
	$i = false;
1151
	
1152
	if (!$lock)
1153
		$lockkey = lock('config');
1154
	if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1155
		conf_mount_rw();
1156
		$backups = get_backups();
1157
		$newbaks = array();
1158
		$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1159
		$baktimes = $backups['versions'];
1160
		$tocache = array();
1161
		unset($backups['versions']);
1162
   		foreach($bakfiles as $backup) { // Check for backups in the directory not represented in the cache.
1163
   			if(filesize($backup) == 0) {
1164
   				unlink($backup);
1165
   				continue;
1166
   			}
1167
			$tocheck = array_shift(explode('.', array_pop(explode('-', $backup))));
1168
            if(!in_array($tocheck, $baktimes)) {
1169
				$i = true;
1170
				if($g['booting'])
1171
					echo ".";
1172
				$newxml = parse_xml_config($backup, $g['xml_rootobj']);
1173
				if($newxml == "-1") {
1174
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1175
					unlink($backup);
1176
					log_error("The backup cache file $backup is corrupted.  Unlinking.");
1177
					continue;
1178
				}
1179
				if($newxml['revision']['description'] == "")
1180
					$newxml['revision']['description'] = "Unknown";
1181
				$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1182
			}
1183
    	}
1184
		foreach($backups as $checkbak) {
1185

    
1186
			if(count(preg_grep('/' . $checkbak['time'] . '/i', $bakfiles)) != 0) {
1187
				$newbaks[] = $checkbak;
1188
			} else {
1189
				$i = true;
1190
				if($g['booting']) print " " . $tocheck . "r";
1191
			}
1192
		}
1193
		foreach($newbaks as $todo) $tocache[$todo['time']] = array('description' => $todo['description']);
1194
		if(is_int($revisions) and (count($tocache) > $revisions)) {
1195
			$toslice = array_slice(array_keys($tocache), 0, $revisions);
1196
			foreach($toslice as $sliced)
1197
				$newcache[$sliced] = $tocache[$sliced];
1198
			foreach($tocache as $version => $versioninfo) {
1199
				if(!in_array($version, array_keys($newcache))) {
1200
					unlink_if_exists($g['conf_path'] . '/backup/config-' . $version . '.xml');
1201
					if($g['booting']) print " " . $tocheck . "d";
1202
				}
1203
			}
1204
			$tocache = $newcache;
1205
		}
1206
		$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1207
        fwrite($bakout, serialize($tocache));
1208
		fclose($bakout);
1209
		conf_mount_ro();
1210
	}
1211
	if($g['booting'] && $i)
1212
		print "done.\n";
1213
	if (!$lock)
1214
		unlock($lockkey);
1215
}
1216

    
1217
function get_backups() {
1218
	global $g;
1219
	if(file_exists("{$g['cf_conf_path']}/backup/backup.cache")) {
1220
		$confvers = unserialize(file_get_contents("{$g['cf_conf_path']}/backup/backup.cache"));
1221
		$bakvers = array_keys($confvers);
1222
		$toreturn = array();
1223
		sort($bakvers);
1224
		// 	$bakvers = array_reverse($bakvers);
1225
		foreach(array_reverse($bakvers) as $bakver)
1226
			$toreturn[] = array('time' => $bakver, 'description' => $confvers[$bakver]['description']);
1227
	} else {
1228
		return false;
1229
	}
1230
	$toreturn['versions'] = $bakvers;
1231
	return $toreturn;
1232
}
1233

    
1234
function backup_config() {
1235
	global $config, $g;
1236

    
1237
	if($g['platform'] == "cdrom")
1238
		return;
1239

    
1240
	conf_mount_rw();
1241

    
1242
	/* Create backup directory if needed */
1243
	safe_mkdir("{$g['cf_conf_path']}/backup");
1244

    
1245
    if($config['revision']['time'] == "") {
1246
            $baktime = 0;
1247
    } else {
1248
            $baktime = $config['revision']['time'];
1249
    }
1250
    if($config['revision']['description'] == "") {
1251
            $bakdesc = "Unknown";
1252
    } else {
1253
            $bakdesc = $config['revision']['description'];
1254
    }
1255
    copy($g['cf_conf_path'] . '/config.xml', $g['cf_conf_path'] . '/backup/config-' . $baktime . '.xml');
1256
    if(file_exists($g['cf_conf_path'] . '/backup/backup.cache')) {
1257
            $backupcache = unserialize(file_get_contents($g['cf_conf_path'] . '/backup/backup.cache'));
1258
    } else {
1259
            $backupcache = array();
1260
    }
1261
    $backupcache[$baktime] = array('description' => $bakdesc);
1262
    $bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1263
    fwrite($bakout, serialize($backupcache));
1264
    fclose($bakout);
1265

    
1266
	conf_mount_ro();
1267

    
1268
	return true;
1269
}
1270

    
1271
function set_device_perms() {
1272
	$devices = array(
1273
		'pf'	=> array(	'user'	=> 'proxy',
1274
					'group'	=> 'proxy',
1275
					'mode'	=> 0660),
1276
		);
1277

    
1278
	foreach ($devices as $name => $attr) {
1279
		$path = "/dev/$name";
1280
		if (file_exists($path)) {
1281
			chown($path, $attr['user']);
1282
			chgrp($path, $attr['group']);
1283
			chmod($path, $attr['mode']);
1284
		}
1285
	}
1286
}
1287

    
1288
?>
(11-11/50)