Project

General

Profile

Download (35.5 KB) Statistics
| Branch: | Tag: | Revision:
1 12df7edc Erik
<?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 e5977136 Scott Ullrich
						$fd = fopen($g['conf_path'] . "/config.xml.tmp", "w");
71 12df7edc Erik
						fwrite($fd, $data);
72
						fclose($fd);
73 e5977136 Scott Ullrich
						exec("/bin/mv {$g['conf_path']}/config.xml.tmp {$g['conf_path']}/config.xml");
74 12df7edc Erik
						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 0af381c2 Scott Ullrich
	$config_parsed = false;
98 12df7edc Erik
	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 e490f995 Ermal
		copy("$file","/cf/conf/config.xml");
196 12df7edc Erik
		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 a45e27ba Ermal
298
	if (refcount_reference(1000) > 1)
299 12df7edc Erik
		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 a45e27ba Ermal
	$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 12df7edc Erik
		$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 23f0ca50 Ermal Lu?i
	/* do not umount on cdrom or pfSense platforms */
333
	if($g['platform'] == "cdrom" or $g['platform'] == "pfSense")
334
		return;
335
336 a45e27ba Ermal
	if (refcount_unreference(1000) > 0)
337 12df7edc Erik
		return;
338
339
	clear_subsystem_dirty('mount');
340
	/* sync data, then force a remount of /cf */
341 b6c34bfc Ermal
	mwexec("/bin/sync; /bin/sync");
342 12df7edc Erik
	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 59cfe65d Ermal
	//ini_set("max_execution_time", "900");
363 12df7edc Erik
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 b96cad97 Seth Mos
	include_once('auth.inc');
383 12df7edc Erik
	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 92cf9fcd sullrich
		if($g['booting'])
392
			echo ".";
393 12df7edc Erik
	}
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 92cf9fcd sullrich
401
	if($g['booting'])
402
		echo "Loading new configuration...";
403 12df7edc Erik
}
404
405 ddd42db3 Ermal Lu?i
/****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 12df7edc Erik
/****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 541989d5 Ermal
		$config['revision']['time'] = time();
468 12df7edc Erik
469
	/* Log the running script so it's not entirely unlogged what changed */
470 42739c1c Ermal Lu?i
	if ($desc == "Unknown")
471 4d52a9b9 jim-p
		$desc = "{$_SERVER['SCRIPT_NAME']} made unknown change";
472 12df7edc Erik
473 4d52a9b9 jim-p
	$config['revision']['description'] = "{$_SESSION['Username']}: " . $desc;
474 362b8147 jim-p
	$config['revision']['username'] = $_SESSION["Username"];
475 12df7edc Erik
476 b6c34bfc Ermal
	conf_mount_rw();
477
	$lockkey = lock('config', LOCK_EX);
478 12df7edc Erik
479
	/* generate configuration XML */
480
	$xmlconfig = dump_xml_config($config, $g['xml_rootobj']);
481
482 41bf8e8e Scott Ullrich
	/* write new configuration */
483
	if (!safe_write_file("{$g['cf_conf_path']}/config.xml", $xmlconfig, false)) {
484 12df7edc Erik
		log_error("WARNING: Config contents could not be save. Could not open file!");
485
		unlock($lockkey);
486 07f1ca1d Ermal
		file_notice("config.xml", "Unable to open {$g['cf_conf_path']}/config.xml for writing in write_config()\n");
487 541989d5 Ermal
		return -1;
488 e5977136 Scott Ullrich
	}
489 41bf8e8e Scott Ullrich
	
490 12df7edc Erik
	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 541989d5 Ermal
	/* NOTE: We assume that the file can be parsed since we wrote it. */
498 12df7edc Erik
	$config = parse_xml_config("{$g['conf_path']}/config.xml", $g['xml_rootobj']);
499 e490f995 Ermal
	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 12df7edc Erik
508
	unlock($lockkey);
509
510
	unlink_if_exists("/usr/local/pkg/pf/carp_sync_client.php");
511 16b96ea6 Scott Ullrich
512 b6c34bfc Ermal
	/* tell kernel to sync fs data */
513
	conf_mount_ro();
514
515 12df7edc Erik
	/* sync carp entries to other firewalls */
516 16b96ea6 Scott Ullrich
	carp_sync_client();
517 12df7edc Erik
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 b6c34bfc Ermal
	if (!$lock)
537
		$lockkey = lock('config', LOCK_EX);
538 12df7edc Erik
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 b6c34bfc Ermal
	conf_mount_ro();
559 12df7edc Erik
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 f2087c85 Scott Ullrich
	conf_mount_rw();
572
	
573 b6c34bfc Ermal
	$lockkey = lock('config', LOCK_EX);
574 12df7edc Erik
575
	unlink_if_exists("{$g['tmp_path']}/config.cache");
576 e490f995 Ermal
	copy($conffile, "{$g['cf_conf_path']}/config.xml");
577 12df7edc Erik
578
	unlock($lockkey);
579
580
	$config = parse_config(true);
581
582
	conf_mount_ro();
583
584 e296b183 Ermal Lu?i
	write_config("Reverted to " . array_pop(explode("/", $conffile)) . ".", false);
585
586 12df7edc Erik
	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 b6c34bfc Ermal
	$lockkey = lock('config', LOCK_EX);
605 12df7edc Erik
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 cace2dbb sullrich
			echo sprintf("% -6s%s%s\t%s\n", $iface, $ifa['mac'],
687 12df7edc Erik
				$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 9d8d8a4c Renato Botelho
			echo "LAN  -> " . $lanif . "\n";
907
		echo "WAN  -> " . $wanif . "\n";
908 12df7edc Erik
		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 65125e11 Ermal
			$config['interfaces']['lan']['enable'] = true;
923 12df7edc Erik
		} 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 d538b8fa Ermal
						mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
936 12df7edc Erik
				}
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 d538b8fa Ermal
				mwexec("/sbin/ifconfig " . $config['interfaces']['lan']['if'] . " delete");
954 12df7edc Erik
			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 65125e11 Ermal
		$config['interfaces']['wan']['enable'] = true;
979 12df7edc Erik
		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 cd25a2b2 jim-p
1141
	conf_mount_rw();
1142
1143
	$backups = get_backups();
1144
	if ($backups) {
1145 12df7edc Erik
		$baktimes = $backups['versions'];
1146
		unset($backups['versions']);
1147 cd25a2b2 jim-p
	} else {
1148
		$backups = array();
1149
		$baktimes = array();
1150
	}
1151
	$newbaks = array();
1152
	$bakfiles = glob($g['cf_conf_path'] . "/backup/config-*");
1153
	$tocache = array();
1154 12df7edc Erik
1155 cd25a2b2 jim-p
	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 12df7edc Erik
			}
1172 cd25a2b2 jim-p
			if($newxml['revision']['description'] == "")
1173
				$newxml['revision']['description'] = "Unknown";
1174
			$tocache[$tocheck] = array('description' => $newxml['revision']['description']);
1175 12df7edc Erik
		}
1176 cd25a2b2 jim-p
	}
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 12df7edc Erik
			}
1195
		}
1196 cd25a2b2 jim-p
		$tocache = $newcache;
1197 12df7edc Erik
	}
1198 cd25a2b2 jim-p
	$bakout = fopen($g['cf_conf_path'] . '/backup/backup.cache', "w");
1199
	fwrite($bakout, serialize($tocache));
1200
	fclose($bakout);
1201
	conf_mount_ro();
1202
1203 12df7edc Erik
	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 573c9548 Ermal
		'pf'	=> array(	'user'	=> 'root',
1266 12df7edc Erik
					'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 42739c1c Ermal Lu?i
?>