From 42f191ba77aa9293098b3327d6415f02483fcf6b Mon Sep 17 00:00:00 2001
From: tbrehm <t.brehm@ispconfig.org>
Date: Thu, 07 Jun 2012 05:09:37 -0400
Subject: [PATCH] Implemented support for UFW firewall (FS#1757 - New IPTables firewall script for IPv4 and IPv6)

---
 install/lib/installer_base.lib.php                          |    9 +
 interface/lib/classes/aps_crawler.inc.php                   |    2 
 interface/web/admin/lib/lang/en_server_config.lng           |    1 
 install/tpl/server.ini.master                               |    1 
 server/plugins-available/firewall_plugin.inc.php            |  229 +++++++++++++++++++++++++++++++++++++++------
 interface/web/admin/form/server_config.tform.php            |    8 +
 interface/web/admin/templates/server_config_server_edit.htm |    6 +
 server/lib/classes/system.inc.php                           |   10 ++
 8 files changed, 232 insertions(+), 34 deletions(-)

diff --git a/install/lib/installer_base.lib.php b/install/lib/installer_base.lib.php
index b472844..9e5c503 100644
--- a/install/lib/installer_base.lib.php
+++ b/install/lib/installer_base.lib.php
@@ -470,6 +470,15 @@
 			if(!$this->dbmaster->query($query)) {
 				$this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
 			}
+			
+			$query = "GRANT SELECT, UPDATE ON ".$value['db'].".`aps_instances` TO '".$value['user']."'@'".$host."' ";
+			if ($verbose){
+				echo $query ."\n";
+			}
+			if(!$this->dbmaster->query($query)) {
+				$this->warning('Unable to set rights of user in master database: '.$value['db']."\n Query: ".$query."\n Error: ".$this->dbmaster->errorMessage);
+			}
+			
 		}
 
 		/*
diff --git a/install/tpl/server.ini.master b/install/tpl/server.ini.master
index 275fa7a..ac4d1a0 100644
--- a/install/tpl/server.ini.master
+++ b/install/tpl/server.ini.master
@@ -11,6 +11,7 @@
 gateway=192.168.0.1
 hostname=server1.domain.tld
 nameservers=192.168.0.1,192.168.0.2
+firewall=bastille
 loglevel=2
 backup_dir=/var/backup
 backup_mode=rootgz
diff --git a/interface/lib/classes/aps_crawler.inc.php b/interface/lib/classes/aps_crawler.inc.php
index e4ca565..9b5b6aa 100644
--- a/interface/lib/classes/aps_crawler.inc.php
+++ b/interface/lib/classes/aps_crawler.inc.php
@@ -61,7 +61,7 @@
             // Check if the cURL module is available
             if(!function_exists('curl_version')) throw new Exception('cURL is not available');
             
-            // Check if used folders are writable (chmod 777)
+            // Check if used folders are writable
             if($this->interface_mode)
             {
                 if(!is_writable($this->interface_pkg_dir)) 
diff --git a/interface/web/admin/form/server_config.tform.php b/interface/web/admin/form/server_config.tform.php
index 24f3f18..6af4498 100644
--- a/interface/web/admin/form/server_config.tform.php
+++ b/interface/web/admin/form/server_config.tform.php
@@ -97,6 +97,14 @@
 			'width' => '15',
 			'maxlength' => '255'
 		),
+		'firewall' => array(
+			'datatype' => 'VARCHAR',
+			'formtype' => 'SELECT',
+			'default' => 'bastille',
+			'value' => array('bastille' => 'bastille', 'ufw' => 'ufw'),
+			'width' => '40',
+			'maxlength' => '255'
+		),
 		'hostname' => array(
 			'datatype' => 'VARCHAR',
 			'formtype' => 'TEXT',
diff --git a/interface/web/admin/lib/lang/en_server_config.lng b/interface/web/admin/lib/lang/en_server_config.lng
index ac7546f..0d237bf 100644
--- a/interface/web/admin/lib/lang/en_server_config.lng
+++ b/interface/web/admin/lib/lang/en_server_config.lng
@@ -162,4 +162,5 @@
 $wb["php_settings_txt"] = 'PHP Settings';
 $wb["apps_vhost_settings_txt"] = 'Apps Vhost Settings';
 $wb["awstats_settings_txt"] = 'AWStats Settings';
+$wb["firewall_txt"] = 'Firewall';
 ?>
\ No newline at end of file
diff --git a/interface/web/admin/templates/server_config_server_edit.htm b/interface/web/admin/templates/server_config_server_edit.htm
index 7b777bf..2d80bca 100644
--- a/interface/web/admin/templates/server_config_server_edit.htm
+++ b/interface/web/admin/templates/server_config_server_edit.htm
@@ -33,6 +33,12 @@
 				<p class="formHint">{tmpl_var name='nameservers_hint_txt'}</p>
 			</div>
 	  <div class="ctrlHolder">
+      	<label for="firewall">{tmpl_var name='firewall_txt'}</label>
+        <select name="firewall" id="firewall" class="selectInput">
+					{tmpl_var name='firewall'}
+				</select>
+      </div>
+	  <div class="ctrlHolder">
       	<label for="loglevel">{tmpl_var name='loglevel_txt'}</label>
         <select name="loglevel" id="loglevel" class="selectInput">
 					{tmpl_var name='loglevel'}
diff --git a/server/lib/classes/system.inc.php b/server/lib/classes/system.inc.php
index 7537ef4..c43a0cc 100644
--- a/server/lib/classes/system.inc.php
+++ b/server/lib/classes/system.inc.php
@@ -1271,6 +1271,16 @@
 		}
 		
 	}
+	
+	//* Check if a application is installed
+	function is_installed($appname) {
+		exec('which '.escapeshellcmd($appname).' 2> /dev/null',$out,$returncode);
+		if(isset($out[0]) && stristr($out[0],$appname) && $returncode == 0) {
+			return true;
+		} else {
+			return false;
+		}
+	}
 
 }
 ?>
diff --git a/server/plugins-available/firewall_plugin.inc.php b/server/plugins-available/firewall_plugin.inc.php
index 6697798..08f735c 100644
--- a/server/plugins-available/firewall_plugin.inc.php
+++ b/server/plugins-available/firewall_plugin.inc.php
@@ -30,12 +30,12 @@
 
 class firewall_plugin {
 	
-	var $plugin_name = 'firewall_plugin';
-	var $class_name  = 'firewall_plugin';
+	private $plugin_name = 'firewall_plugin';
+	private $class_name  = 'firewall_plugin';
 	
 	//* This function is called during ispconfig installation to determine
 	//  if a symlink shall be created for this plugin.
-	function onInstall() {
+	public function onInstall() {
 		global $conf;
 		
 		if($conf['bastille']['installed'] = true && $conf['services']['firewall'] == true) {
@@ -51,7 +51,7 @@
 	 	This function is called when the plugin is loaded
 	*/
 	
-	function onLoad() {
+	public function onLoad() {
 		global $app;
 		
 		/*
@@ -62,51 +62,182 @@
 		$app->plugins->registerEvent('firewall_insert',$this->plugin_name,'insert');
 		$app->plugins->registerEvent('firewall_update',$this->plugin_name,'update');
 		$app->plugins->registerEvent('firewall_delete',$this->plugin_name,'delete');
-		
-		
 	}
 	
 	
-	function insert($event_name,$data) {
+	public function insert($event_name,$data) {
 		global $app, $conf;
 		
 		$this->update($event_name,$data);
 		
 	}
 	
-	function update($event_name,$data) {
+	public function update($event_name,$data) {
 		global $app, $conf;
 		
-		$tcp_ports = '';
-		$udp_ports = '';
+		//* load the server configuration options
+		$app->uses('getconf');
+		$server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
+		if($server_config['firewall'] == 'ufw') {
+			$this->ufw_update($event_name,$data);
+		} else {
+			$this->bastille_update($event_name,$data);
+		}
 		
-		$ports = explode(',',$data['new']['tcp_port']);
-		if(is_array($ports)) {
-			foreach($ports as $p) {
-				if(strstr($p,':')) {
-					$p_parts = explode(':',$p);
-					$p_clean = intval($p_parts[0]).':'.intval($p_parts[1]);
-				} else {
-					$p_clean = intval($p);
-				}
-				$tcp_ports .= $p_clean . ' ';
+	}
+	
+	public function delete($event_name,$data) {
+		global $app, $conf;
+		
+		//* load the server configuration options
+		$app->uses('getconf');
+		$server_config = $app->getconf->get_server_config($conf['server_id'], 'server');
+		
+		if($server_config['firewall'] == 'ufw') {
+			$this->ufw_delete($event_name,$data);
+		} else {
+			$this->bastille_delete($event_name,$data);
+		}
+		
+	}
+	
+	private function ufw_update($event_name,$data) {
+		global $app, $conf;
+		
+		$app->uses('system');
+		
+		if(!$app->system->is_installed('ufw')) {
+			$app->log('UFW Firewall is not installed',LOGLEVEL_WARN);
+			return false;
+		}
+		
+		exec('ufw --version',$out);
+		$parts = explode(' ',$out[0]);
+		$ufwversion = $parts[1];
+		unset($parts);
+		unset($out);
+
+		if(version_compare ( $ufwversion , '0.30') < 0) {
+			$app->log('The installed UFW Firewall version is too old. Minimum required version 0.30',LOGLEVEL_WARN);
+			return false;
+		}
+		
+		//* Basic firewall setup when the firewall is added the first time
+		if($event_name == 'firewall_insert') {
+			exec('ufw --force disable');
+			exec('ufw --force reset');
+			exec('ufw default deny incoming');
+			exec('ufw default allow outgoing');
+		}
+		
+		$tcp_ports_new = $this->clean_ports($data['new']['tcp_port'],',');
+		$tcp_ports_old = $this->clean_ports($data['old']['tcp_port'],',');
+		$udp_ports_new = $this->clean_ports($data['new']['udp_port'],',');
+		$udp_ports_old = $this->clean_ports($data['old']['udp_port'],',');
+		
+		$tcp_ports_new_array = explode(',',$tcp_ports_new);
+		$tcp_ports_old_array = explode(',',$tcp_ports_old);
+		$udp_ports_new_array = explode(',',$udp_ports_new);
+		$udp_ports_old_array = explode(',',$udp_ports_old);
+		
+		//* add tcp ports
+		foreach($tcp_ports_new_array as $port) {
+			if(!in_array($port,$tcp_ports_old_array) && $port > 0) {
+				exec('ufw allow '.$port.'/tcp');
+				$app->log('ufw allow '.$port.'/tcp',LOGLEVEL_DEBUG);
+				sleep(1);
 			}
 		}
-		$tcp_ports = trim($tcp_ports);
 		
-		$ports = explode(',',$data['new']['udp_port']);
-		if(is_array($ports)) {
-			foreach($ports as $p) {
-				if(strstr($p,':')) {
-					$p_parts = explode(':',$p);
-					$p_clean = intval($p_parts[0]).':'.intval($p_parts[1]);
-				} else {
-					$p_clean = intval($p);
-				}
-				$udp_ports .= $p_clean . ' ';
+		//* remove tcp ports
+		foreach($tcp_ports_old_array as $port) {
+			if(!in_array($port,$tcp_ports_new_array) && $port > 0) {
+				exec('ufw delete allow '.$port.'/tcp');
+				$app->log('ufw delete allow '.$port.'/tcp',LOGLEVEL_DEBUG);
+				sleep(1);
 			}
 		}
-		$udp_ports = trim($udp_ports);
+		
+		//* add udp ports
+		foreach($udp_ports_new_array as $port) {
+			if(!in_array($port,$udp_ports_old_array) && $port > 0) {
+				exec('ufw allow '.$port.'/udp');
+				$app->log('ufw allow '.$port.'/udp',LOGLEVEL_DEBUG);
+				sleep(1);
+			}
+		}
+		
+		//* remove udp ports
+		foreach($udp_ports_old_array as $port) {
+			if(!in_array($port,$udp_ports_new_array) && $port > 0) {
+				exec('ufw delete allow '.$port.'/udp');
+				$app->log('ufw delete allow '.$port.'/udp',LOGLEVEL_DEBUG);
+				sleep(1);
+			}
+		}
+		
+		/*
+		if($tcp_ports_new != $tcp_ports_old) {
+			exec('ufw allow to any proto tcp port '.$tcp_ports_new);
+			$app->log('ufw allow to any proto tcp port '.$tcp_ports_new,LOGLEVEL_DEBUG);
+			if($event_name == 'firewall_update') {
+				exec('ufw delete allow to any proto tcp port '.$tcp_ports_old);
+				$app->log('ufw delete allow to any proto tcp port '.$tcp_ports_old,LOGLEVEL_DEBUG);
+			}
+		}
+		
+		if($udp_ports_new != $udp_ports_old) {
+			exec('ufw allow to any proto udp port '.$udp_ports_new);
+			$app->log('ufw allow to any proto udp port '.$udp_ports_new,LOGLEVEL_DEBUG);
+			if($event_name == 'firewall_update') {
+				exec('ufw delete allow to any proto udp port '.$udp_ports_old);
+				$app->log('ufw delete allow to any proto udp port '.$udp_ports_old,LOGLEVEL_DEBUG);
+			}
+		}
+		*/
+		
+		if($data['new']['active'] == 'y') {
+			if($data['new']['active'] == $data['old']['active']) {
+				exec('ufw reload');
+				$app->log('Reloading the firewall',LOGLEVEL_DEBUG);
+			} else {
+				//* Ensure that bastille firewall is stopped
+				exec($conf['init_scripts'] . '/' . 'bastille-firewall stop');
+				if(@is_file('/etc/debian_version')) exec('update-rc.d -f bastille-firewall remove');
+			
+				//* Start ufw firewall
+				exec('ufw --force enable');
+				$app->log('Starting the firewall',LOGLEVEL_DEBUG);
+			}
+		} else {
+			exec('ufw disable');
+			$app->log('Stopping the firewall',LOGLEVEL_DEBUG);
+		}
+	}
+	
+	private function ufw_delete($event_name,$data) {
+		global $app, $conf;
+		
+		$app->uses('system');
+		
+		if(!$app->system->is_installed('ufw')) {
+			$app->log('UFW Firewall is not installed',LOGLEVEL_DEBUG);
+			return false;
+		}
+		
+		exec('ufw --force reset');
+		exec('ufw disable');
+		$app->log('Stopping the firewall',LOGLEVEL_DEBUG);
+		
+	}
+	
+	private function bastille_update($event_name,$data) {
+		global $app, $conf;
+		
+		$app->uses('system');
+		
+		$tcp_ports = $this->clean_ports($data['new']['tcp_port'],' ');
+		$udp_ports = $this->clean_ports($data['new']['udp_port'],' ');
 		
 		$app->load('tpl');
 		$tpl = new tpl();
@@ -120,6 +251,10 @@
 		unset($tpl);
 		
 		if($data['new']['active'] == 'y') {
+			//* ensure that ufw firewall is disabled in case both firewalls are installed
+			if($app->system->is_installed('ufw')) {
+				exec('ufw disable');
+			}
 			exec($conf['init_scripts'] . '/' . 'bastille-firewall restart');
 			if(@is_file('/etc/debian_version')) exec('update-rc.d bastille-firewall defaults');
 			$app->log('Restarting the firewall',LOGLEVEL_DEBUG);
@@ -132,7 +267,7 @@
 		
 	}
 	
-	function delete($event_name,$data) {
+	private function bastille_delete($event_name,$data) {
 		global $app, $conf;
 		
 		exec($conf['init_scripts'] . '/' . 'bastille-firewall stop');
@@ -142,6 +277,34 @@
 	}
 	
 	
+	private function clean_ports($portlist,$spacer) {
+		
+		$ports = explode(',',$portlist);
+		$ports_out = '';
+		
+		if(is_array($ports)) {
+			foreach($ports as $p) {
+				$p_clean = '';
+				if(strstr($p,':')) {
+					$p_parts = explode(':',$p);
+					$tmp_lower = intval($p_parts[0]);
+					$tmp_higher = intval($p_parts[1]);
+					if($tmp_lower > 0 && $tmp_lower <= 65535 && $tmp_higher > 0 && $tmp_higher <= 65535 && $tmp_lower < $tmp_higher) {
+						$p_clean = $tmp_lower.':'.$tmp_higher;
+					}
+				} else {
+					$tmp = intval($p);
+					if($tmp > 0 && $tmp <= 65535) {
+						$p_clean = $tmp;
+					}
+				}
+				if($p_clean != '') $ports_out .= $p_clean . $spacer;
+				
+			}
+		}
+		return substr($ports_out,0,strlen($spacer)*-1);
+	}
+	
 	
 
 } // end class

--
Gitblit v1.9.1