support pooling of IP ranges (RFE 107)

This commit is contained in:
Roland Gruber 2014-09-13 14:43:44 +00:00
parent 2131405664
commit 6d86cef692
11 changed files with 496 additions and 149 deletions

View File

@ -1,5 +1,6 @@
September 2014 4.7 September 2014 4.7
- Nginx webserver support - Nginx webserver support
- DHCP: support pooling of IP ranges (RFE 107)
- Personal: support pager attribute (hidden by default) - Personal: support pager attribute (hidden by default)
- renamed config/lam.conf_sample to lam.conf.sample and config.cfg_sample to config.cfg.sample - renamed config/lam.conf_sample to lam.conf.sample and config.cfg_sample to config.cfg.sample
- LAM Pro: - LAM Pro:

View File

@ -4243,9 +4243,12 @@ Attention: If the Active Directory schema is used then LAM will always use dn an
<title>DHCP</title> <title>DHCP</title>
<para>You can mange your DHCP server with LAM. It supports to manage <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 subnets, fixed IP entries, IP ranges and DDNS.</para>
by adding the account type DHCP to your server profile. Please also add
the DHCP modules.</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 <para>LAM requires that you use an LDAP entry with the object class
"dhcpService" or "dhcpServer" as suffix for this account type. If the "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>
</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 <para><emphasis role="bold">Example server
entry:</emphasis><code></code></para> entry:</emphasis><code></code></para>
@ -4375,6 +4408,10 @@ Run slapindex to rebuild the index.
<para>IP ranges may be specified.</para> <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> <screenshot>
<mediaobject> <mediaobject>
<imageobject> <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

View File

@ -624,7 +624,7 @@ class htmlInputField extends htmlElement {
} }
/** /**
* Sets the field size. * Sets the field size (default is 30).
* *
* @param int $fieldSize size * @param int $fieldSize size
*/ */

View File

@ -41,7 +41,7 @@ $Id$
class fixed_ip extends baseModule { class fixed_ip extends baseModule {
/** fixed ips */ /** fixed ips */
public $fixed_ip; public $fixed_ip = array();
/** already processed? */ /** already processed? */
public $processed = false; public $processed = false;

View File

@ -52,6 +52,11 @@ class range extends baseModule {
/** For check, if IPs overlaped. */ /** For check, if IPs overlaped. */
public $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. * 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'); $return['attributes'] = array('dhcpRange');
// help Entries // help Entries
$return['help'] = array( $return['help'] = array(
'range_from' => array( 'range_from' => array(
"Headline" => _("Range from"), "Headline" => _("Range from"),
"Text" => _("The starting IP address of the range.") "Text" => _("The starting IP address of the range.")
) , 'range_to' => array( ),
'range_to' => array(
"Headline" => _("Range to"), "Headline" => _("Range to"),
"Text" => _("The ending IP address of the range.") "Text" => _("The ending IP address of the range.")
) , 'drop_range' => array( ),
'drop_range' => array(
"Headline" => _("Delete range"), "Headline" => _("Delete range"),
"Text" => _("Deletes an IP range.") "Text" => _("Deletes an IP range.")
) , 'add_range' => array( ),
'add_range' => array(
"Headline" => _("New range"), "Headline" => _("New range"),
"Text" => _("Adds input fields for a new IP 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 // available PDF fields
$return['PDF_fields'] = array('ranges' => _('Ranges')); $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['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['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['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')) { if ($this->getAccountContainer()->dn_orig!=$_SESSION['config']->get_suffix('dhcp')) {
$this->orig = $attr; $this->orig = $attr;
$this->attributes = $attr; $this->attributes = $attr;
// Load DHCP Options: // Load DHCP Options:
if (isset($attr['dhcpRange']) && is_array($attr['dhcpRange'])) { if (isset($attr['dhcpRange']) && is_array($attr['dhcpRange'])) {
natcasesort($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]); $this->ranges[$id] = array('range_start'=>$ex[0],'range_end'=>$ex[1]);
} }
} }
// load pools
$this->loadPools();
} }
} }
@ -290,104 +313,168 @@ class range extends baseModule {
*/ */
public function process_attributes() { public function process_attributes() {
$errors = array(); $errors = array();
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]!="") {
$droped = false; // Was a Range droped??? foreach($this->ranges AS $id=>$arr) {
if ($this->getAccountContainer()->dn_orig!=$_SESSION['config']->get_suffix('dhcp')) { // Check if range is to drop
if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]!="") { if (isset($_POST['drop_range_'.$id])) {
$was_a_error = false; // drop Range:
$this->reset_overlaped_range(); unset($this->ranges[$id]);
unset($this->attributes['dhcpRange'][$id]);
continue;
}
foreach($this->ranges AS $id=>$arr) { // 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];
// Check if range is to drop // Check end:
if (isset($_POST['drop_range_'.$id])) { $_POST['range_end_'.$id] = trim($_POST['range_end_'.$id]);
// Drop Range: if (!check_ip($_POST['range_end_'.$id])) {
unset($this->ranges[$id]); $errorOccured = true;
unset($this->attributes['dhcpRange'][$id]); }
$droped = true; $this->ranges[$id]['range_end'] = $_POST['range_end_'.$id];
continue;
}
// if the inputs are empty, then do nothing: // Check if ip overlaped:
if ($_POST['range_start_'.$id]=="" && $_POST['range_end_'.$id]=="") { if(!$this->overlaped_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) {
unset($this->attributes['dhcpRange'][$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 { else {
$mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); unset($this->attributes['dhcpRange'][$id]);
// 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];
}
// Check end: // Add new Range
$_POST['range_end_'.$id] = trim($_POST['range_end_'.$id]); if(isset($_POST['add_range'])) {
if (!check_ip($_POST['range_end_'.$id])) { // Check, if there where no errors:
$this->ranges[$id]['range_end'] = $_POST['range_end_'.$id]; if ($errorOccured) {
$was_a_error = true; $errors[] = $this->messages['add_range'][0];
} }
else else
{ {
$this->ranges[$id]['range_end'] = $_POST['range_end_'.$id]; // Add Range:
} $this->ranges[] = array('range_start'=>'','range_end'=>'');
}
}
// Check if ip overlaped: // update pool data
if(!$this->overlaped_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { foreach ($this->poolsNew as $index => $pool) {
$was_a_error = true; // delete pool
} if (isset($_POST['del_pool_' . $index])) {
unset($this->poolsNew[$index]);
// Check if Subnet and range first are valid: continue;
if (!range::check_subnet_range($_POST['range_start_'.$id],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { }
$was_a_error = true; // name
} $this->poolsNew[$index]['cn'][0] = trim($_POST['pool_cn_' . $index]);
if (empty($this->poolsNew[$index]['cn'][0])) {
// Check if Subnet and range last are valid: $errors[] = $this->messages['pool_cn'][0];
if (!range::check_subnet_range($_POST['range_end_'.$id],$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0], $mask)) { }
$was_a_error = true; // failover peer
} $peer = trim($_POST['pool_peer_' . $index]);
if (!empty($this->poolsNew[$index]['dhcpstatements'])) {
// Check if Range is valid // remove old peer setting
if (!$this->check_range($_POST['range_start_'.$id],$_POST['range_end_'.$id])) { foreach ($this->poolsNew[$index]['dhcpstatements'] as $indexS => $stmt) {
$was_a_error = true; if (strpos($stmt, 'failover peer "') === 0) {
} unset($this->poolsNew[$index]['dhcpstatements'][$indexS]);
break;
// 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]);
}
} }
} }
} }
if (!empty($peer)) {
// Check if there was a error: $this->poolsNew[$index]['dhcpstatements'][] = 'failover peer "' . $peer . '"';
if ($was_a_error) {
$errors[] = $this->messages['range_errors'][0];
} }
if (!empty($this->poolsNew[$index]['dhcprange'])) {
// Add new Range foreach ($this->poolsNew[$index]['dhcprange'] as $rIndex => $range) {
if(isset($_POST['add_range'])) { // delete pool range
// Check, if there where no errors: if (isset($_POST['drop_poolrange_' . $index . '_' . $rIndex])) {
if ($was_a_error) { unset($this->poolsNew[$index]['dhcprange'][$rIndex]);
$errors[] = $this->messages['add_range'][0]; continue;
} }
else $from = trim($_POST['pool_from_' . $index . '_' . $rIndex]);
{ $to = trim($_POST['pool_to_' . $index . '_' . $rIndex]);
// Add Range: if (empty($from) && empty($to)) {
$this->ranges[] = array('range_start'=>'','range_end'=>''); 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;
}
}
} }
} }
// check if at least one range is still set
if (empty($this->poolsNew[$index]['dhcprange'])) {
$this->processed = true; $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; return $errors;
} }
@ -400,66 +487,257 @@ class range extends baseModule {
$return = new htmlTable(); $return = new htmlTable();
if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]=="") { if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]=="") {
$return->addElement(new htmlStatusMessage('INFO', _("Please fill out the DHCP settings first."))); $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 $ranges is not a array, then create it
if (!is_array($this->ranges)) { if (!is_array($this->ranges)) {
$this->ranges = array(); $this->ranges = array();
} }
$this->reset_overlaped_range(); $this->reset_overlaped_range();
$mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'); $mask = $this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask');
foreach($this->ranges AS $id=>$arr) { $subnet = $this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0];
foreach($this->ranges AS $id=>$arr) {
// Range start // Range start
$error = ""; $error = "";
if (isset($this->ranges[$id]['range_start']) && !empty($this->ranges[$id]['range_start'])) { if (isset($this->ranges[$id]['range_start']) && !empty($this->ranges[$id]['range_start'])) {
if ($this->processed && !check_ip($this->ranges[$id]['range_start'])) { if ($this->processed && !check_ip($this->ranges[$id]['range_start'])) {
$error = _("The IP address is invalid."); $error = _("The IP address is invalid.");
} elseif($this->processed && !$this->check_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end'])) { } 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."); $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)) { } elseif ($this->processed && !range::check_subnet_range($this->ranges[$id]['range_start'], $subnet, $mask)) {
$error = _("The IP does not match the subnet."); $error = _("The IP does not match the subnet.");
} elseif ($this->processed && !$this->overlaped_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end']) ) { } elseif ($this->processed && !$this->overlaped_range($this->ranges[$id]['range_start'],$this->ranges[$id]['range_end']) ) {
$error = _("The range conflicts with another range."); $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);
} }
$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);
// add new range $return->addElement(new htmlSpacer(null, '10px'), true);
$addButton = new htmlButton('add_range', _('New range'));
$addButton->colspan = 2;
$return->addElement($addButton);
$return->addElement(new htmlHelpLink('add_range'));
} }
// 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; 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. * Returns a list of modifications which have to be made to the LDAP account.
* *
@ -502,6 +780,20 @@ class range extends baseModule {
return $return; 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;
}
} }
?> ?>

View File

@ -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>"; $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); natcasesort($ranges);
echo implode('', $ranges); echo implode('', $ranges);
echo"</table>"; echo"</table>";

View File

@ -216,6 +216,11 @@ table.collapse {
background-position: 0px 0px !important; background-position: 0px 0px !important;
} }
.trashButton {
background-image: url(../graphics/trash.png) !important;
background-position: 0px 0px !important;
}
.smallPadding span { .smallPadding span {
padding: 0.1em 0.4em !important; padding: 0.1em 0.4em !important;
} }