support pooling of IP ranges (RFE 107)
This commit is contained in:
		
							parent
							
								
									2131405664
								
							
						
					
					
						commit
						6d86cef692
					
				|  | @ -1,5 +1,6 @@ | |||
| September 2014 4.7 | ||||
|   - Nginx webserver support | ||||
|   - DHCP: support pooling of IP ranges (RFE 107) | ||||
|   - Personal: support pager attribute (hidden by default) | ||||
|   - renamed config/lam.conf_sample to lam.conf.sample and config.cfg_sample to config.cfg.sample | ||||
|   - LAM Pro: | ||||
|  |  | |||
|  | @ -4243,9 +4243,12 @@ Attention: If the Active Directory schema is used then LAM will always use dn an | |||
|       <title>DHCP</title> | ||||
| 
 | ||||
|       <para>You can mange your DHCP server with LAM. It supports to manage | ||||
|       subnets, fixed IP entries, IP ranges and DDNS. The DHCP can be activated | ||||
|       by adding the account type DHCP to your server profile. Please also add | ||||
|       the DHCP modules.</para> | ||||
|       subnets, fixed IP entries, IP ranges and DDNS.</para> | ||||
| 
 | ||||
|       <para><emphasis role="bold">Configuration</emphasis></para> | ||||
| 
 | ||||
|       <para>The DHCP management can be activated by adding the account type | ||||
|       DHCP to your server profile. Please also add the DHCP modules.</para> | ||||
| 
 | ||||
|       <para>LAM requires that you use an LDAP entry with the object class | ||||
|       "dhcpService" or "dhcpServer" as suffix for this account type. If the | ||||
|  | @ -4256,6 +4259,36 @@ Attention: If the Active Directory schema is used then LAM will always use dn an | |||
|       <literallayout> | ||||
| </literallayout> | ||||
| 
 | ||||
|       <para>Add account type:</para> | ||||
| 
 | ||||
|       <screenshot> | ||||
|         <mediaobject> | ||||
|           <imageobject> | ||||
|             <imagedata fileref="images/dhcpConf1.png" /> | ||||
|           </imageobject> | ||||
|         </mediaobject> | ||||
|       </screenshot> | ||||
| 
 | ||||
|       <para>Set suffix:</para> | ||||
| 
 | ||||
|       <screenshot> | ||||
|         <mediaobject> | ||||
|           <imageobject> | ||||
|             <imagedata fileref="images/dhcpConf2.png" /> | ||||
|           </imageobject> | ||||
|         </mediaobject> | ||||
|       </screenshot> | ||||
| 
 | ||||
|       <para>Add modules:</para> | ||||
| 
 | ||||
|       <screenshot> | ||||
|         <mediaobject> | ||||
|           <imageobject> | ||||
|             <imagedata fileref="images/dhcpConf3.png" /> | ||||
|           </imageobject> | ||||
|         </mediaobject> | ||||
|       </screenshot> | ||||
| 
 | ||||
|       <para><emphasis role="bold">Example server | ||||
|       entry:</emphasis><code></code></para> | ||||
| 
 | ||||
|  | @ -4375,6 +4408,10 @@ Run slapindex to rebuild the index. | |||
| 
 | ||||
|       <para>IP ranges may be specified.</para> | ||||
| 
 | ||||
|       <para>If you use failover pools for your IP ranges please use the pool | ||||
|       options on the bottom. Here you can add DHCP pools (object class | ||||
|       "dhcpPool") and specify the failover peer.</para> | ||||
| 
 | ||||
|       <screenshot> | ||||
|         <mediaobject> | ||||
|           <imageobject> | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 11 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 13 KiB | 
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 22 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 73 KiB | 
|  | @ -624,7 +624,7 @@ class htmlInputField extends htmlElement { | |||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Sets the field size. | ||||
| 	 * Sets the field size (default is 30). | ||||
| 	 *  | ||||
| 	 * @param int $fieldSize size | ||||
| 	 */ | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ $Id$ | |||
| class fixed_ip extends baseModule { | ||||
| 
 | ||||
| 	/** fixed ips */ | ||||
| 	public $fixed_ip; | ||||
| 	public $fixed_ip = array(); | ||||
| 	 | ||||
| 	/** already processed? */ | ||||
| 	public $processed = false; | ||||
|  |  | |||
|  | @ -51,6 +51,11 @@ class range extends baseModule { | |||
| 	 | ||||
| 	/** For check, if IPs overlaped. */ | ||||
| 	public $overlaped; | ||||
| 	 | ||||
| 	/** list of pools that currently exist in LDAP */ | ||||
| 	private $poolsOrig = array(); | ||||
| 	/** list of pools that need to be updated in LDAP */ | ||||
| 	private $poolsNew = array(); | ||||
| 
 | ||||
| 	/** | ||||
| 	* Returns true if this module can manage accounts of the current type, otherwise false. | ||||
|  | @ -88,19 +93,35 @@ class range extends baseModule { | |||
| 		$return['attributes'] = array('dhcpRange'); | ||||
| 		// help Entries
 | ||||
| 		$return['help'] = array( | ||||
| 				'range_from' => array( | ||||
| 			'range_from' => array( | ||||
| 				"Headline" => _("Range from"), | ||||
| 				"Text" => _("The starting IP address of the range.") | ||||
| 			) , 'range_to' => array( | ||||
| 			), | ||||
| 			'range_to' => array( | ||||
| 				"Headline" => _("Range to"), | ||||
| 				"Text" => _("The ending IP address of the range.") | ||||
| 			) , 'drop_range' => array( | ||||
| 			), | ||||
| 			'drop_range' => array( | ||||
| 				"Headline" => _("Delete range"), | ||||
| 				"Text" => _("Deletes an IP range.") | ||||
| 			) , 'add_range' => array( | ||||
| 			), | ||||
| 			'add_range' => array( | ||||
| 				"Headline" => _("New range"), | ||||
| 				"Text" => _("Adds input fields for a new IP range.") | ||||
| 			) ); | ||||
| 			), | ||||
| 			'add_pool' => array( | ||||
| 				"Headline" => _("New pool"), | ||||
| 				"Text" => _("Adds a new range pool.") | ||||
| 			), | ||||
| 			'poolName' => array( | ||||
| 				"Headline" => _("Name"), 'attr' => 'cn', | ||||
| 				"Text" => _("The pool's name.") | ||||
| 			), | ||||
| 			'poolPeer' => array( | ||||
| 				"Headline" => _("Failover peer"), 'attr' => 'dhcpStatements', | ||||
| 				"Text" => _("The pool's failover peer.") | ||||
| 			), | ||||
| 			); | ||||
| 			 | ||||
| 		// available PDF fields
 | ||||
| 		$return['PDF_fields'] = array('ranges' => _('Ranges')); | ||||
|  | @ -114,6 +135,8 @@ class range extends baseModule { | |||
| 		$this->messages['range_errors'][0] = array('ERROR', _('One or more errors occured. The invalid fields are marked.'), ''); | ||||
| 		$this->messages['add_range'][0] = array('ERROR', _('New range'), _('Adding the range failed because errors occured.')); | ||||
| 		$this->messages['drop_range'][0] = array('ERROR', _('Delete range'), _('It is not possible to delete all ranges.')); | ||||
| 		$this->messages['pool_cn'][0] = array('ERROR', _('Name'), _('Please enter a pool name.')); | ||||
| 		$this->messages['pool_range'][0] = array('ERROR', _('Please enter at least one range for pool "%s".'), null); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
|  | @ -225,8 +248,6 @@ class range extends baseModule { | |||
|         if ($this->getAccountContainer()->dn_orig!=$_SESSION['config']->get_suffix('dhcp')) { | ||||
| 			$this->orig = $attr; | ||||
| 			$this->attributes = $attr; | ||||
| 
 | ||||
| 
 | ||||
| 			// Load DHCP Options:
 | ||||
| 	        if (isset($attr['dhcpRange']) && is_array($attr['dhcpRange'])) { | ||||
| 	        	natcasesort($attr['dhcpRange']); | ||||
|  | @ -237,6 +258,8 @@ class range extends baseModule { | |||
| 					$this->ranges[$id] = array('range_start'=>$ex[0],'range_end'=>$ex[1]); | ||||
| 				} | ||||
| 			} | ||||
| 			// load pools
 | ||||
| 			$this->loadPools(); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | @ -290,107 +313,171 @@ class range extends baseModule { | |||
| 	*/ | ||||
| 	public function process_attributes() { | ||||
| 		$errors = array(); | ||||
| 		 | ||||
| 		$droped = false;    // Was a Range droped???
 | ||||
| 		if ($this->getAccountContainer()->dn_orig!=$_SESSION['config']->get_suffix('dhcp')) { | ||||
| 			if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]!="") { | ||||
| 			    $was_a_error = false; | ||||
| 			    $this->reset_overlaped_range(); | ||||
| 		if ($this->getAccountContainer()->dn_orig == $_SESSION['config']->get_suffix('dhcp')) { | ||||
| 			return $errors; | ||||
| 		} | ||||
| 		$subnet = $this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]; | ||||
| 		$mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); | ||||
| 	    $errorOccured = false; | ||||
| 	    $this->reset_overlaped_range(); | ||||
| 		if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]!="") { | ||||
| 
 | ||||
| 			    foreach($this->ranges AS $id=>$arr) { | ||||
| 		    foreach($this->ranges AS $id=>$arr) { | ||||
| 		        // Check if range is to drop
 | ||||
| 			    if (isset($_POST['drop_range_'.$id])) { | ||||
| 					// drop Range:
 | ||||
| 					unset($this->ranges[$id]); | ||||
| 					unset($this->attributes['dhcpRange'][$id]); | ||||
| 			        continue; | ||||
| 			    } | ||||
| 
 | ||||
| 			        // Check if range is to drop
 | ||||
| 				    if (isset($_POST['drop_range_'.$id])) { | ||||
| 						// Drop Range:
 | ||||
| 						unset($this->ranges[$id]); | ||||
| 						unset($this->attributes['dhcpRange'][$id]); | ||||
| 				        $droped = true; | ||||
| 				        continue; | ||||
| 				    } | ||||
| 		        // if the inputs are empty, then do nothing:
 | ||||
| 		        if ($_POST['range_start_'.$id]=="" && $_POST['range_end_'.$id]=="") { | ||||
| 		            unset($this->attributes['dhcpRange'][$id]); | ||||
| 		        } | ||||
| 		        else { | ||||
| 					// Check range_start:
 | ||||
| 					$_POST['range_start_'.$id] = trim($_POST['range_start_'.$id]); | ||||
| 			        if (!check_ip($_POST['range_start_'.$id])) { | ||||
| 			        	$errorOccured = true; | ||||
| 			        } | ||||
| 		            $this->ranges[$id]['range_start'] = $_POST['range_start_'.$id]; | ||||
| 
 | ||||
| 			        // if the inputs are empty, then do nothing:
 | ||||
| 			        if ($_POST['range_start_'.$id]=="" && $_POST['range_end_'.$id]=="") { | ||||
| 			            unset($this->attributes['dhcpRange'][$id]); | ||||
| 					// Check end:
 | ||||
| 					$_POST['range_end_'.$id] = trim($_POST['range_end_'.$id]); | ||||
| 			        if (!check_ip($_POST['range_end_'.$id])) { | ||||
| 			        	$errorOccured = true; | ||||
| 			        } | ||||
| 		            $this->ranges[$id]['range_end'] = $_POST['range_end_'.$id]; | ||||
| 
 | ||||
| 			        // Check if ip overlaped:
 | ||||
| 			        if(!$this->overlaped_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { | ||||
| 			            $errorOccured = true; | ||||
| 			        } | ||||
| 
 | ||||
| 					// Check if Subnet and range first are valid:
 | ||||
| 					if (!range::check_subnet_range($_POST['range_start_'.$id], $subnet, $mask)) { | ||||
| 					    $errorOccured = true; | ||||
| 					} | ||||
| 
 | ||||
| 					// Check if Subnet and range last are valid:
 | ||||
| 					if (!range::check_subnet_range($_POST['range_end_'.$id], $subnet, $mask)) { | ||||
| 					    $errorOccured = true; | ||||
| 					} | ||||
| 
 | ||||
| 			        // Check if Range is valid
 | ||||
| 			        if (!$this->check_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { | ||||
| 			            $errorOccured = true; | ||||
| 			        } | ||||
| 
 | ||||
| 			        // Check, if range_start and range_end are ok!
 | ||||
| 			        if (!$errorOccured) { | ||||
| 			            $this->attributes['dhcpRange'][$id] = $_POST['range_start_'.$id]." ".$_POST['range_end_'.$id]; | ||||
| 			        } | ||||
| 			        else { | ||||
| 			        	$mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); | ||||
| 						// Check range_start:
 | ||||
| 						$_POST['range_start_'.$id] = trim($_POST['range_start_'.$id]); | ||||
| 				        if (!check_ip($_POST['range_start_'.$id])) { | ||||
| 				        	$this->ranges[$id]['range_start'] = $_POST['range_start_'.$id]; | ||||
| 				        	$was_a_error = true; | ||||
| 				        } | ||||
| 				        else | ||||
| 				        { | ||||
| 				            $this->ranges[$id]['range_start'] = $_POST['range_start_'.$id]; | ||||
| 				        } | ||||
| 			            unset($this->attributes['dhcpRange'][$id]); | ||||
| 			        } | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 						// Check end:
 | ||||
| 						$_POST['range_end_'.$id] = trim($_POST['range_end_'.$id]); | ||||
| 				        if (!check_ip($_POST['range_end_'.$id])) { | ||||
| 				        	$this->ranges[$id]['range_end'] = $_POST['range_end_'.$id]; | ||||
| 				        	$was_a_error = true; | ||||
| 				        } | ||||
| 				        else | ||||
| 				        { | ||||
| 				            $this->ranges[$id]['range_end'] = $_POST['range_end_'.$id]; | ||||
| 				        } | ||||
| 
 | ||||
| 				        // Check if ip overlaped:
 | ||||
| 				        if(!$this->overlaped_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { | ||||
| 				            $was_a_error = true; | ||||
| 				        } | ||||
| 
 | ||||
| 						// Check if Subnet and range first are valid:
 | ||||
| 						if (!range::check_subnet_range($_POST['range_start_'.$id],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { | ||||
| 						    $was_a_error = true; | ||||
| 						} | ||||
| 
 | ||||
| 						// Check if Subnet and range last are valid:
 | ||||
| 						if (!range::check_subnet_range($_POST['range_end_'.$id],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { | ||||
| 						    $was_a_error = true; | ||||
| 						} | ||||
| 
 | ||||
| 				        // Check if Range is valid
 | ||||
| 				        if (!$this->check_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { | ||||
| 				            $was_a_error = true; | ||||
| 				        } | ||||
| 
 | ||||
| 				        // Check, if range_start and range_end are ok!
 | ||||
| 				        if (!$was_a_error) { | ||||
| 				            $this->attributes['dhcpRange'][$id] = $_POST['range_start_'.$id]." ".$_POST['range_end_'.$id]; | ||||
| 				        } | ||||
| 				        else { | ||||
| 				            unset($this->attributes['dhcpRange'][$id]); | ||||
| 				        } | ||||
| 		// Add new Range
 | ||||
| 		if(isset($_POST['add_range'])) { | ||||
| 			// Check, if there where no errors:
 | ||||
| 			if ($errorOccured) { | ||||
| 			    $errors[] = $this->messages['add_range'][0]; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 			    // Add Range:
 | ||||
| 			    $this->ranges[] = array('range_start'=>'','range_end'=>''); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// update pool data
 | ||||
| 		foreach ($this->poolsNew as $index => $pool) { | ||||
| 			// delete pool
 | ||||
| 			if (isset($_POST['del_pool_' . $index])) { | ||||
| 				unset($this->poolsNew[$index]); | ||||
| 				continue; | ||||
| 			} | ||||
| 			// name
 | ||||
| 			$this->poolsNew[$index]['cn'][0] = trim($_POST['pool_cn_' . $index]); | ||||
| 			if (empty($this->poolsNew[$index]['cn'][0])) { | ||||
| 				$errors[] = $this->messages['pool_cn'][0]; | ||||
| 			} | ||||
| 			// failover peer
 | ||||
| 			$peer = trim($_POST['pool_peer_' . $index]); | ||||
| 			if (!empty($this->poolsNew[$index]['dhcpstatements'])) { | ||||
| 				// remove old peer setting
 | ||||
| 				foreach ($this->poolsNew[$index]['dhcpstatements'] as $indexS => $stmt) { | ||||
| 					if (strpos($stmt, 'failover peer "') === 0) { | ||||
| 						unset($this->poolsNew[$index]['dhcpstatements'][$indexS]); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Check if there was a error:
 | ||||
| 			if ($was_a_error) { | ||||
| 			    $errors[] = $this->messages['range_errors'][0]; | ||||
| 			if (!empty($peer)) { | ||||
| 				$this->poolsNew[$index]['dhcpstatements'][] = 'failover peer "' . $peer . '"'; | ||||
| 			} | ||||
| 
 | ||||
| 			// Add new Range
 | ||||
| 			if(isset($_POST['add_range'])) { | ||||
| 				// Check, if there where no errors:
 | ||||
| 				if ($was_a_error) { | ||||
| 				    $errors[] = $this->messages['add_range'][0]; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 				    // Add Range:
 | ||||
| 				    $this->ranges[] = array('range_start'=>'','range_end'=>''); | ||||
| 			if (!empty($this->poolsNew[$index]['dhcprange'])) { | ||||
| 				foreach ($this->poolsNew[$index]['dhcprange'] as $rIndex => $range) { | ||||
| 					// delete pool range
 | ||||
| 					if (isset($_POST['drop_poolrange_' . $index . '_' . $rIndex])) { | ||||
| 						unset($this->poolsNew[$index]['dhcprange'][$rIndex]); | ||||
| 						continue; | ||||
| 					} | ||||
| 					$from = trim($_POST['pool_from_' . $index . '_' . $rIndex]); | ||||
| 					$to = trim($_POST['pool_to_' . $index . '_' . $rIndex]); | ||||
| 					if (empty($from) && empty($to)) { | ||||
| 						unset($this->poolsNew[$index]['dhcprange'][$rIndex]); | ||||
| 					} | ||||
| 					else { | ||||
| 						$this->poolsNew[$index]['dhcprange'][$rIndex] = $from . ' ' . $to; | ||||
| 						// check ranges
 | ||||
| 						if (!check_ip($from) || !check_ip($to)) { | ||||
| 							$errorOccured = true; | ||||
| 						} | ||||
| 						elseif (!$this->overlaped_range($from, $to)) { | ||||
| 							$errorOccured = true; | ||||
| 						} | ||||
| 						elseif (!range::check_subnet_range($from, $subnet, $mask) || !range::check_subnet_range($to, $subnet, $mask)) { | ||||
| 							$errorOccured = true; | ||||
| 						} | ||||
| 						elseif (!$this->check_range($from, $to)) { | ||||
| 							$errorOccured = true; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			$this->processed = true; | ||||
| 			// check if at least one range is still set
 | ||||
| 			if (empty($this->poolsNew[$index]['dhcprange'])) { | ||||
| 				$error = $this->messages['pool_range'][0]; | ||||
| 				$error[] = array(htmlspecialchars($this->poolsNew[$index]['cn'][0])); | ||||
| 				$errors[] = $error; | ||||
| 			} | ||||
| 			// add pool range
 | ||||
| 			if (isset($_POST['add_poolrange_' . $index])) { | ||||
| 				$this->poolsNew[$index]['dhcprange'][] = ''; | ||||
| 			} | ||||
| 		} | ||||
| 		// add a new pool
 | ||||
| 		if (isset($_POST['add_pool'])) { | ||||
| 			$this->poolsNew[] = array( | ||||
| 				'objectclass' => array('dhcpPool'), | ||||
| 				'dhcprange' => array('') | ||||
| 			); | ||||
| 		} | ||||
| 		 | ||||
| 		// Check if there was a error:
 | ||||
| 		if ($errorOccured) { | ||||
| 		    $errors[] = $this->messages['range_errors'][0]; | ||||
| 		} | ||||
| 
 | ||||
| 		$this->processed = true; | ||||
| 		return $errors; | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Returns the HTML meta data for the main account page. | ||||
| 	 *  | ||||
|  | @ -400,66 +487,257 @@ class range extends baseModule { | |||
| 		$return = new htmlTable(); | ||||
| 		if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]=="") { | ||||
| 			$return->addElement(new htmlStatusMessage('INFO', _("Please fill out the DHCP settings first."))); | ||||
| 			return $return; | ||||
|         } | ||||
|         else { | ||||
|          | ||||
|             // If $ranges is not a array, then create it
 | ||||
|             if (!is_array($this->ranges)) { | ||||
|             	$this->ranges = array(); | ||||
|             } | ||||
|             $this->reset_overlaped_range(); | ||||
|             $mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); | ||||
|             foreach($this->ranges AS $id=>$arr) { | ||||
| 
 | ||||
| 				// Range start
 | ||||
| 				$error = ""; | ||||
| 				if (isset($this->ranges[$id]['range_start']) && !empty($this->ranges[$id]['range_start'])) { | ||||
| 					if ($this->processed && !check_ip($this->ranges[$id]['range_start'])) { | ||||
| 					    $error = _("The IP address is invalid."); | ||||
| 					} elseif($this->processed && !$this->check_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end'])) { | ||||
| 	                    $error = _("The range end needs to be greater than the range start."); | ||||
| 					} elseif ($this->processed && !range::check_subnet_range($this->ranges[$id]['range_start'],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { | ||||
| 						$error = _("The IP does not match the subnet."); | ||||
| 					} elseif ($this->processed && !$this->overlaped_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end']) ) { | ||||
| 						$error = _("The range conflicts with another range."); | ||||
| 					} | ||||
|         // If $ranges is not a array, then create it
 | ||||
|         if (!is_array($this->ranges)) { | ||||
| 	       	$this->ranges = array(); | ||||
|         } | ||||
|         $this->reset_overlaped_range(); | ||||
|         $mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); | ||||
|         $subnet = $this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]; | ||||
|         foreach($this->ranges AS $id=>$arr) { | ||||
| 			// Range start
 | ||||
| 			$error = ""; | ||||
| 			if (isset($this->ranges[$id]['range_start']) && !empty($this->ranges[$id]['range_start'])) { | ||||
| 				if ($this->processed && !check_ip($this->ranges[$id]['range_start'])) { | ||||
| 				    $error = _("The IP address is invalid."); | ||||
| 				} elseif($this->processed && !$this->check_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end'])) { | ||||
|                     $error = _("The range end needs to be greater than the range start."); | ||||
| 				} elseif ($this->processed && !range::check_subnet_range($this->ranges[$id]['range_start'], $subnet, $mask)) { | ||||
| 					$error = _("The IP does not match the subnet."); | ||||
| 				} elseif ($this->processed && !$this->overlaped_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end']) ) { | ||||
| 					$error = _("The range conflicts with another range."); | ||||
| 				} | ||||
| 				$fromInput = new htmlTableExtendedInputField(_('Range from'), 'range_start_'.$id, $this->ranges[$id]['range_start'], 'range_from'); | ||||
| 				$fromInput->setRequired(true); | ||||
| 				$return->addElement($fromInput); | ||||
| 				$return->addElement(new htmlOutputText($error), true); | ||||
| 				// Range end
 | ||||
| 				$error = ""; | ||||
| 				if (isset($this->ranges[$id]['range_end']) && !empty($this->ranges[$id]['range_end'])) { | ||||
| 					if ($this->processed && !check_ip($this->ranges[$id]['range_end'])) { | ||||
| 					    $error = _("The IP address is invalid."); | ||||
| 					} elseif ($this->processed && !range::check_subnet_range($this->ranges[$id]['range_end'],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { | ||||
| 						$error = _("The IP does not match the subnet."); | ||||
| 					} | ||||
| 				} | ||||
| 				$toInput = new htmlTableExtendedInputField(_('Range to'), 'range_end_'.$id, $this->ranges[$id]['range_end'], 'range_to'); | ||||
| 				$toInput->setRequired(true); | ||||
| 				$return->addElement($toInput); | ||||
| 				$return->addElement(new htmlOutputText($error), true); | ||||
| 				// Drop range:
 | ||||
| 				$dropButton = new htmlButton('drop_range_'.$id, _('Delete range')); | ||||
| 				$dropButton->colspan = 2; | ||||
| 				$return->addElement($dropButton); | ||||
| 				$return->addElement(new htmlHelpLink('drop_range'), true); | ||||
| 
 | ||||
| 				$return->addElement(new htmlSpacer(null, '10px'), true); | ||||
| 			} | ||||
| 			 | ||||
| 			// add new range
 | ||||
| 			$addButton = new htmlButton('add_range', _('New range')); | ||||
| 			$addButton->colspan = 2; | ||||
| 			$return->addElement($addButton); | ||||
| 			$return->addElement(new htmlHelpLink('add_range')); | ||||
| 			$fromInput = new htmlTableExtendedInputField(_('Range from'), 'range_start_'.$id, $this->ranges[$id]['range_start'], 'range_from'); | ||||
| 			$fromInput->setRequired(true); | ||||
| 			$return->addElement($fromInput); | ||||
| 			$return->addElement(new htmlOutputText($error), true); | ||||
| 			// Range end
 | ||||
| 			$error = ""; | ||||
| 			if (isset($this->ranges[$id]['range_end']) && !empty($this->ranges[$id]['range_end'])) { | ||||
| 				if ($this->processed && !check_ip($this->ranges[$id]['range_end'])) { | ||||
| 				    $error = _("The IP address is invalid."); | ||||
| 				} elseif ($this->processed && !range::check_subnet_range($this->ranges[$id]['range_end'], $subnet, $mask)) { | ||||
| 					$error = _("The IP does not match the subnet."); | ||||
| 				} | ||||
| 			} | ||||
| 			$toInput = new htmlTableExtendedInputField(_('Range to'), 'range_end_'.$id, $this->ranges[$id]['range_end'], 'range_to'); | ||||
| 			$toInput->setRequired(true); | ||||
| 			$return->addElement($toInput); | ||||
| 			$return->addElement(new htmlOutputText($error), true); | ||||
| 			// Drop range:
 | ||||
| 			$dropButton = new htmlButton('drop_range_'.$id, _('Delete range')); | ||||
| 			$dropButton->colspan = 2; | ||||
| 			$dropButton->setIconClass('deleteButton'); | ||||
| 			$return->addElement($dropButton); | ||||
| 			$return->addElement(new htmlHelpLink('drop_range'), true); | ||||
| 
 | ||||
| 			$return->addElement(new htmlSpacer(null, '10px'), true); | ||||
| 		} | ||||
| 		 | ||||
| 		// add new range
 | ||||
| 		$addButton = new htmlButton('add_range', _('New range')); | ||||
| 		$addButton->setIconClass('createButton'); | ||||
| 		$addButton->colspan = 2; | ||||
| 		$return->addElement($addButton); | ||||
| 		$return->addElement(new htmlHelpLink('add_range'), true); | ||||
| 		 | ||||
| 		// pools
 | ||||
| 		if (!empty($this->poolsNew)) { | ||||
| 			$return->addElement(new htmlSubTitle(_('Pools')), true); | ||||
| 			foreach ($this->poolsNew as $index => $poolAttrs) { | ||||
| 				$cn = !empty($poolAttrs['cn'][0]) ? $poolAttrs['cn'][0] : ''; | ||||
| 				$nameField = new htmlTableExtendedInputField(_('Name'), 'pool_cn_' . $index, $cn, 'poolName'); | ||||
| 				$nameField->setRequired(true); | ||||
| 				$return->addElement($nameField); | ||||
| 				$delPoolButton = new htmlButton('del_pool_' . $index, _('Delete pool')); | ||||
| 				$delPoolButton->setIconClass('trashButton'); | ||||
| 				$return->addElement($delPoolButton, true); | ||||
| 				$peer = ''; | ||||
| 				if (!empty($poolAttrs['dhcpstatements'])) { | ||||
| 					foreach ($poolAttrs['dhcpstatements'] as $statement) { | ||||
| 						if (strpos($statement, 'failover peer "') === 0) { | ||||
| 							$peer = substr($statement, strlen('failover peer "'), -1); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				$return->addElement(new htmlTableExtendedInputField(_('Failover peer'), 'pool_peer_' . $index, $peer, 'poolPeer'), true); | ||||
| 				$return->addVerticalSpace('10px'); | ||||
| 				if (!empty($poolAttrs['dhcprange'])) { | ||||
| 					foreach ($poolAttrs['dhcprange'] as $rIndex => $range) { | ||||
| 						$range = explode(' ', $range); | ||||
| 						$from = !empty($range[0]) ? $range[0] : ''; | ||||
| 						$to = !empty($range[1]) ? $range[1] : ''; | ||||
| 						$fromInput = new htmlTableExtendedInputField(_('Range from'), 'pool_from_' . $index . '_' . $rIndex, $from, 'range_from'); | ||||
| 						$fromInput->setRequired(true); | ||||
| 						$toInput = new htmlTableExtendedInputField(_('Range to'), 'pool_to_' . $index . '_' . $rIndex, $to, 'range_to'); | ||||
| 						$toInput->setRequired(true); | ||||
| 						$return->addElement($fromInput); | ||||
| 						$message = ''; | ||||
| 						if (!empty($from) && $this->processed) { | ||||
| 							if (!check_ip($from)) { | ||||
| 								$message = _("The IP address is invalid."); | ||||
| 							} | ||||
| 							elseif (!$this->check_range($from, $to)) { | ||||
| 								$message = _("The range end needs to be greater than the range start."); | ||||
| 							} | ||||
| 							elseif (!range::check_subnet_range($from, $subnet, $mask)) { | ||||
| 								$message = _("The IP does not match the subnet."); | ||||
| 							} | ||||
| 							elseif (!$this->overlaped_range($from, $to)) { | ||||
| 								$message = _("The range conflicts with another range."); | ||||
| 							} | ||||
| 						} | ||||
| 						$return->addElement(new htmlOutputText($message), true); | ||||
| 						$return->addElement($toInput); | ||||
| 						$message = ''; | ||||
| 						if (!empty($to) && $this->processed) { | ||||
| 							if (!check_ip($to)) { | ||||
| 								$message = _("The IP address is invalid."); | ||||
| 							} | ||||
| 							elseif (!range::check_subnet_range($to, $subnet, $mask)) { | ||||
| 								$message = _("The IP does not match the subnet."); | ||||
| 							} | ||||
| 						} | ||||
| 						$return->addElement(new htmlOutputText($message), true); | ||||
| 						// drop range
 | ||||
| 						$dropButton = new htmlButton('drop_poolrange_' . $index . '_' . $rIndex, _('Delete range')); | ||||
| 						$dropButton->colspan = 2; | ||||
| 						$dropButton->setIconClass('deleteButton'); | ||||
| 						$return->addElement($dropButton); | ||||
| 						$return->addElement(new htmlHelpLink('drop_range'), true); | ||||
| 						$return->addElement(new htmlSpacer(null, '10px'), true); | ||||
| 					} | ||||
| 				} | ||||
| 				// add new range
 | ||||
| 				$newButton = new htmlButton('add_poolrange_' . $index, _('New range')); | ||||
| 				$newButton->colspan = 2; | ||||
| 				$newButton->setIconClass('createButton'); | ||||
| 				$return->addElement($newButton); | ||||
| 				$return->addElement(new htmlHelpLink('add_range'), true); | ||||
| 				$return->addVerticalSpace('20px'); | ||||
| 			} | ||||
| 			$return->addVerticalSpace('20px'); | ||||
| 		} | ||||
| 		 | ||||
| 		// add new range pool
 | ||||
| 		$addButton = new htmlButton('add_pool', _('New pool')); | ||||
| 		$addButton->setIconClass('createButton'); | ||||
| 		$addButton->colspan = 2; | ||||
| 		$return->addElement($addButton); | ||||
| 		$return->addElement(new htmlHelpLink('add_pool'), true); | ||||
| 		 | ||||
| 		return $return; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Allows the module to run commands after the LDAP entry is changed or created. | ||||
| 	 *  | ||||
| 	 * Calling this method requires the existence of an enclosing {@link accountContainer}. | ||||
| 	 * | ||||
| 	 * @param boolean $newAccount new account | ||||
| 	 * @param array $attributes LDAP attributes of this entry | ||||
| 	 * @return array array which contains status messages. Each entry is an array containing the status message parameters. | ||||
| 	 */ | ||||
| 	public function postModifyActions($newAccount, $attributes) { | ||||
| 		$errors = array(); | ||||
| 		// update pool data
 | ||||
| 		// add new pools
 | ||||
| 		foreach ($this->poolsNew as $pool) { | ||||
| 			$found = false; | ||||
| 			foreach ($this->poolsOrig as $poolOrig) { | ||||
| 				if ($pool['cn'][0] == $poolOrig['cn'][0]) { | ||||
| 					$found = true; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!$found) { | ||||
| 				// create new pool
 | ||||
| 				$dn = 'cn=' . $pool['cn'][0] . ',' . $this->getAccountContainer()->finalDN; | ||||
| 				if (isset($pool['dn'])) { | ||||
| 					unset($pool['dn']); | ||||
| 				} | ||||
| 				$success = @ldap_add($_SESSION['ldap']->server(), $dn, $pool); | ||||
| 				if (!$success) { | ||||
| 					$msg = sprintf(_('Was unable to create DN: %s.'), $dn); | ||||
| 					logNewMessage(LOG_ERR, $msg . getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 					$errors[] = array('ERROR', $msg, getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// update existing pools
 | ||||
| 		foreach ($this->poolsNew as $pool) { | ||||
| 			foreach ($this->poolsOrig as $poolOrig) { | ||||
| 				if ($pool['cn'][0] == $poolOrig['cn'][0]) { | ||||
| 					// check for changes
 | ||||
| 					$mod = array(); | ||||
| 					// check attributes
 | ||||
| 					$attrs = array('dhcpstatements', 'dhcprange'); | ||||
| 					foreach ($attrs as $attr) { | ||||
| 						$changed = false; | ||||
| 						if (empty($pool[$attr]) && empty($poolOrig[$attr])) { | ||||
| 							continue; | ||||
| 						} | ||||
| 						if ((!empty($pool[$attr]) && empty($poolOrig[$attr])) | ||||
| 								|| (empty($pool[$attr]) && !empty($poolOrig[$attr])) | ||||
| 								|| (sizeof($pool[$attr]) != sizeof($poolOrig[$attr]))) { | ||||
| 							$changed = true; | ||||
| 						} | ||||
| 						else { | ||||
| 							sort($pool[$attr]); | ||||
| 							sort($poolOrig[$attr]); | ||||
| 							foreach ($pool[$attr] as $index => $val) { | ||||
| 								if ($val != $poolOrig[$attr][$index]) { | ||||
| 									$changed = true; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						if ($changed && isset($pool[$attr])) { | ||||
| 							$mod[$attr] = $pool[$attr]; | ||||
| 						} | ||||
| 						elseif ($changed) { | ||||
| 							$mod[$attr] = array(); | ||||
| 						} | ||||
| 					} | ||||
| 					if (!empty($mod)) { | ||||
| 						$dn = 'cn=' . $pool['cn'][0] . ',' . $this->getAccountContainer()->finalDN; | ||||
| 						$success = @ldap_modify($_SESSION['ldap']->server(), $dn, $mod); | ||||
| 						if (!$success) { | ||||
| 							$msg = sprintf(_('Was unable to modify attributes of DN: %s.'), $dn); | ||||
| 							logNewMessage(LOG_ERR, $msg . getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 							$errors[] = array('ERROR', $msg, getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 						} | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// delete obsolete pools
 | ||||
| 		foreach ($this->poolsOrig as $poolOrig) { | ||||
| 			$found = false; | ||||
| 			foreach ($this->poolsNew as $pool) { | ||||
| 				if ($poolOrig['cn'][0] == $pool['cn'][0]) { | ||||
| 					$found = true; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			if (!$found) { | ||||
| 				// delete pool
 | ||||
| 				$dn = 'cn=' . $poolOrig['cn'][0] . ',' . $this->getAccountContainer()->finalDN; | ||||
| 				$success = @ldap_delete($_SESSION['ldap']->server(), $dn); | ||||
| 				if (!$success) { | ||||
| 					$msg = sprintf(_('Was unable to delete DN: %s.'), $dn); | ||||
| 					logNewMessage(LOG_ERR, $msg . getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 					$errors[] = array('ERROR', $msg, getDefaultLDAPErrorString($_SESSION['ldap']->server())); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return $errors; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	* Returns a list of modifications which have to be made to the LDAP account. | ||||
| 	* | ||||
|  | @ -502,6 +780,20 @@ class range extends baseModule { | |||
| 		return $return; | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Loads the list of pools from LDAP. | ||||
| 	 */ | ||||
| 	private function loadPools() { | ||||
| 		$dn = $this->getAccountContainer()->dn_orig; | ||||
| 		$this->poolsOrig = searchLDAP($dn, '(objectclass=dhcpPool)', array('*')); | ||||
| 		foreach ($this->poolsOrig as &$pool) { | ||||
| 			if (!empty($pool['dhcprange'])) { | ||||
| 				sort($pool['dhcprange']); | ||||
| 			} | ||||
| 		} | ||||
| 		$this->poolsNew = $this->poolsOrig; | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| ?>
 | ||||
|  |  | |||
|  | @ -238,6 +238,18 @@ class lamDHCPList extends lamList { | |||
| 						$ranges[] = "<tr><td>".$ex[0]."</td><td width=\"20\"><center>-</center></td><td>".$ex[1]."</td></tr>"; | ||||
| 					} | ||||
| 				} | ||||
| 				$pooledRanges = searchLDAP($entry['dn'], '(objectclass=dhcpPool)', array('dhcprange')); | ||||
| 				foreach ($pooledRanges as $pool) { | ||||
| 					if (empty($pool['dhcprange'])) { | ||||
| 						continue; | ||||
| 					} | ||||
| 					foreach($pool['dhcprange'] AS $id => $value) { | ||||
| 						if (!empty($value) && !is_numeric($value)) { | ||||
| 							$ex = explode(" ", $value); | ||||
| 							$ranges[] = "<tr><td>".$ex[0]."</td><td width=\"20\"><center>-</center></td><td>".$ex[1]."</td></tr>"; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				natcasesort($ranges); | ||||
| 				echo implode('', $ranges); | ||||
| 				echo"</table>"; | ||||
|  |  | |||
|  | @ -216,6 +216,11 @@ table.collapse { | |||
| 	background-position: 0px 0px !important; | ||||
| } | ||||
| 
 | ||||
| .trashButton { | ||||
| 	background-image: url(../graphics/trash.png) !important; | ||||
| 	background-position: 0px 0px !important; | ||||
| } | ||||
| 
 | ||||
| .smallPadding span { | ||||
| 	padding: 0.1em 0.4em !important; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue