diff --git a/lam/HISTORY b/lam/HISTORY index c4525e65..c7760dea 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -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: diff --git a/lam/docs/manual-sources/howto.xml b/lam/docs/manual-sources/howto.xml index ba4cd35c..b83feaf9 100644 --- a/lam/docs/manual-sources/howto.xml +++ b/lam/docs/manual-sources/howto.xml @@ -4243,9 +4243,12 @@ Attention: If the Active Directory schema is used then LAM will always use dn an DHCP 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. + subnets, fixed IP entries, IP ranges and DDNS. + + Configuration + + The DHCP management can be activated by adding the account type + DHCP to your server profile. Please also add the DHCP modules. 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 + Add account type: + + + + + + + + + + Set suffix: + + + + + + + + + + Add modules: + + + + + + + + + Example server entry: @@ -4375,6 +4408,10 @@ Run slapindex to rebuild the index. IP ranges may be specified. + 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. + diff --git a/lam/docs/manual-sources/images/dhcpConf1.png b/lam/docs/manual-sources/images/dhcpConf1.png new file mode 100644 index 00000000..ac065498 Binary files /dev/null and b/lam/docs/manual-sources/images/dhcpConf1.png differ diff --git a/lam/docs/manual-sources/images/dhcpConf2.png b/lam/docs/manual-sources/images/dhcpConf2.png new file mode 100644 index 00000000..dc47c315 Binary files /dev/null and b/lam/docs/manual-sources/images/dhcpConf2.png differ diff --git a/lam/docs/manual-sources/images/dhcpConf3.png b/lam/docs/manual-sources/images/dhcpConf3.png new file mode 100644 index 00000000..7111326e Binary files /dev/null and b/lam/docs/manual-sources/images/dhcpConf3.png differ diff --git a/lam/docs/manual-sources/images/ranges.png b/lam/docs/manual-sources/images/ranges.png index 43e25be6..2bc7c4da 100644 Binary files a/lam/docs/manual-sources/images/ranges.png and b/lam/docs/manual-sources/images/ranges.png differ diff --git a/lam/lib/html.inc b/lam/lib/html.inc index 19849bf1..12f0eebd 100644 --- a/lam/lib/html.inc +++ b/lam/lib/html.inc @@ -624,7 +624,7 @@ class htmlInputField extends htmlElement { } /** - * Sets the field size. + * Sets the field size (default is 30). * * @param int $fieldSize size */ diff --git a/lam/lib/modules/fixed_ip.inc b/lam/lib/modules/fixed_ip.inc index eeb829d5..dad8ce86 100644 --- a/lam/lib/modules/fixed_ip.inc +++ b/lam/lib/modules/fixed_ip.inc @@ -41,7 +41,7 @@ $Id$ class fixed_ip extends baseModule { /** fixed ips */ - public $fixed_ip; + public $fixed_ip = array(); /** already processed? */ public $processed = false; diff --git a/lam/lib/modules/range.inc b/lam/lib/modules/range.inc index e74da9b0..a8f02d2c 100644 --- a/lam/lib/modules/range.inc +++ b/lam/lib/modules/range.inc @@ -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; + } + } ?> diff --git a/lam/lib/types/dhcp.inc b/lam/lib/types/dhcp.inc index 4390a118..b9e067fb 100644 --- a/lam/lib/types/dhcp.inc +++ b/lam/lib/types/dhcp.inc @@ -238,6 +238,18 @@ class lamDHCPList extends lamList { $ranges[] = "".$ex[0]."
-
".$ex[1].""; } } + $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[] = "".$ex[0]."
-
".$ex[1].""; + } + } + } natcasesort($ranges); echo implode('', $ranges); echo""; diff --git a/lam/style/500_layout.css b/lam/style/500_layout.css index f6755fa7..ddc21612 100644 --- a/lam/style/500_layout.css +++ b/lam/style/500_layout.css @@ -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; }