check for duplicate host name

This commit is contained in:
Roland Gruber 2018-11-23 20:05:41 +01:00
parent 2d3f584bb4
commit bb9a1b1719
1 changed files with 296 additions and 224 deletions

View File

@ -7,7 +7,7 @@ $Id$
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/) This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2008 Thomas Manninger Copyright (C) 2008 Thomas Manninger
2008 - 2017 Roland Gruber 2008 - 2018 Roland Gruber
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -61,6 +61,9 @@ class fixed_ip extends baseModule {
/** cached host entries (list of array('cn' => ..., 'iphostnumber' => ..., 'macaddress' => ...)) */ /** cached host entries (list of array('cn' => ..., 'iphostnumber' => ..., 'macaddress' => ...)) */
private $hostCache = null; private $hostCache = null;
/** cache for existing host entries */
private $existingDhcpHostsCache = null;
/** /**
* 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.
* *
@ -287,110 +290,111 @@ class fixed_ip extends baseModule {
*/ */
public function process_attributes() { public function process_attributes() {
$errors = array(); $errors = array();
if (!$this->isRootNode()) { if ($this->isRootNode()) {
$this->processed = true; return $errors;
}
$this->processed = true;
$this->reset_overlapd_ip(); $this->reset_overlapd_ip();
if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]!="") { if ($this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0]!="") {
$error = false; // errors by process_attributes()? $error = false; // errors by process_attributes()?
$pcs = array(); $pcs = array();
foreach($this->fixed_ip AS $id=>$arr) { foreach($this->fixed_ip AS $id=>$arr) {
// Check if ip is to drop // Check if ip is to drop
if (isset($_POST['drop_ip_'.$id])) { if (isset($_POST['drop_ip_'.$id])) {
// Drop ip: // Drop ip:
unset($this->fixed_ip[$id]); unset($this->fixed_ip[$id]);
continue; continue;
} }
// MAC address // MAC address
$_POST['mac_'.$id] = strtolower(trim($_POST['mac_'.$id])); $_POST['mac_'.$id] = strtolower(trim($_POST['mac_'.$id]));
$invalid = $this->check_mac($_POST['mac_'.$id]); $invalid = $this->check_mac($_POST['mac_'.$id]);
if ($invalid) { if ($invalid) {
$error = true;
}
$this->fixed_ip[$id]['mac'] = $_POST['mac_'.$id];
// description
if (!get_preg($_POST['description_'.$id], 'ascii')) {
$error = true;
}
$this->fixed_ip[$id]['description'] = $_POST['description_'.$id];
// active
$this->fixed_ip[$id]['active'] = (isset($_POST['active_' . $id]) && ($_POST['active_' . $id] == 'on'));
// Ip address
if (!empty($_POST['ip_'.$id])) {
$_POST['ip_'.$id] = trim($_POST['ip_'.$id]);
}
if (!empty($_POST['ip_'.$id]) && !(check_ip($_POST['ip_'.$id]))) {
$error = true;
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id];
}
elseif (!empty($_POST['ip_'.$id]) && !$this->overlapd_ip($_POST['ip_'.$id])) {
$error = true;
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id];
}
else {
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id];
}
// Is ip correct with subnet:
if (!empty($_POST['ip_'.$id]) && check_ip($_POST['ip_'.$id]) && !range::check_subnet_range($_POST['ip_'.$id],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'))) {
$error = true;
}
// cn:
if (!empty($_POST['pc_'.$id])) $_POST['pc_'.$id] = trim($_POST['pc_'.$id]);
if (!empty($_POST['pc_'.$id])) {
// name already in use
if (in_array($_POST['pc_'.$id], $pcs) ) {
$error = true; $error = true;
} }
$this->fixed_ip[$id]['mac'] = $_POST['mac_'.$id];
// description
if (!get_preg($_POST['description_'.$id], 'ascii')) {
$error = true;
}
$this->fixed_ip[$id]['description'] = $_POST['description_'.$id];
// active
$this->fixed_ip[$id]['active'] = (isset($_POST['active_' . $id]) && ($_POST['active_' . $id] == 'on'));
// Ip address
if (!empty($_POST['ip_'.$id])) {
$_POST['ip_'.$id] = trim($_POST['ip_'.$id]);
}
if (!empty($_POST['ip_'.$id]) && !(check_ip($_POST['ip_'.$id]))) {
$error = true;
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id];
}
elseif (!empty($_POST['ip_'.$id]) && !$this->overlapd_ip($_POST['ip_'.$id])) {
$error = true;
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id];
}
else { else {
$this->fixed_ip[$id]['ip'] = $_POST['ip_'.$id]; $pcs[] = $_POST['pc_'.$id];
} }
// Is ip correct with subnet:
if (!empty($_POST['ip_'.$id]) && check_ip($_POST['ip_'.$id]) && !range::check_subnet_range($_POST['ip_'.$id],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'))) {
$error = true;
}
// cn:
if (!empty($_POST['pc_'.$id])) $_POST['pc_'.$id] = trim($_POST['pc_'.$id]);
if (!empty($_POST['pc_'.$id])) {
// Already use?
if (in_array($_POST['pc_'.$id], $pcs) ) {
$error = true;
}
else {
$pcs[] = $_POST['pc_'.$id];
}
}
else {
$error = true;
}
if (strlen($_POST['pc_'.$id])>30) {
$error = true;
}
if (!preg_match("/^[A-Za-z0-9\\._-]*$/",$_POST['pc_'.$id])) {
$error = true;
}
$this->fixed_ip[$id]['cn'] = $_POST['pc_'.$id];
} }
if ($error) { else {
$errors[] = $this->messages['errors'][0]; $error = true;
} }
if (strlen($_POST['pc_'.$id])>30) {
$error = true;
}
if (!preg_match("/^[A-Za-z0-9\\._-]*$/",$_POST['pc_'.$id])) {
$error = true;
}
$this->fixed_ip[$id]['cn'] = $_POST['pc_'.$id];
} }
if ($error) {
$errors[] = $this->messages['errors'][0];
}
}
// Add new IP // Add new IP
if (isset($_POST['add_ip']) || ($_POST['pc_add'] != '') || ($_POST['mac_add'] != '')) { if (isset($_POST['add_ip']) || ($_POST['pc_add'] != '') || ($_POST['mac_add'] != '')) {
// Add IP: // Add IP:
$active = (isset($_POST['active_add']) && ($_POST['active_add'] == 'on')); $active = (isset($_POST['active_add']) && ($_POST['active_add'] == 'on'));
$dhcpstatements = array(); $dhcpstatements = array();
$this->setActive($dhcpstatements, $active); $this->setActive($dhcpstatements, $active);
$this->setIP($dhcpstatements, $_POST['ip_add']); $this->setIP($dhcpstatements, $_POST['ip_add']);
$this->fixed_ip[] = array( $this->fixed_ip[] = array(
'cn' => $_POST['pc_add'], 'cn' => $_POST['pc_add'],
'mac' => $_POST['mac_add'], 'mac' => $_POST['mac_add'],
'description' => $_POST['description_add'], 'description' => $_POST['description_add'],
'ip' => $_POST['ip_add'], 'ip' => $_POST['ip_add'],
'dhcpstatements' => $dhcpstatements, 'dhcpstatements' => $dhcpstatements,
'active' => $active, 'active' => $active,
); );
$this->orderByIP(); $this->orderByIP();
}
} }
return $errors; return $errors;
@ -407,151 +411,202 @@ class fixed_ip extends baseModule {
$return->addElement(new htmlStatusMessage('ERROR', _("Please fill out the DHCP settings first.")), true); $return->addElement(new htmlStatusMessage('ERROR', _("Please fill out the DHCP settings first.")), true);
return $return; return $return;
} }
else { $this->initCache();
$this->initCache(); // auto-completion for host names
// auto-completion for host names $autoNames = array();
$autoNames = array(); if (!empty($this->hostCache) && (sizeof($this->hostCache) < 200)) {
if (!empty($this->hostCache) && (sizeof($this->hostCache) < 200)) { foreach ($this->hostCache as $index => $attrs) {
foreach ($this->hostCache as $index => $attrs) { if (!empty($attrs['cn'][0])) {
if (!empty($attrs['cn'][0])) { $autoNames[] = $attrs['cn'][0];
$autoNames[] = $attrs['cn'][0];
}
} }
$autoNames = array_values(array_unique($autoNames));
} }
// caption $autoNames = array_values(array_unique($autoNames));
$ipContainer = new htmlTable(); }
$ipContainer->addElement(new htmlOutputText(_('IP address'))); // caption
$ipContainer->addElement(new htmlHelpLink('ip')); $ipContainer = new htmlTable();
$return->addElement($ipContainer); $ipContainer->addElement(new htmlOutputText(_('IP address')));
$pcContainer = new htmlTable(); $ipContainer->addElement(new htmlHelpLink('ip'));
$pcContainer->addElement(new htmlOutputText(_('PC name'), true, true)); $return->addElement($ipContainer);
$pcContainer->addElement(new htmlHelpLink('pc')); $pcContainer = new htmlTable();
$return->addElement($pcContainer); $pcContainer->addElement(new htmlOutputText(_('PC name'), true, true));
$macContainer = new htmlTable(); $pcContainer->addElement(new htmlHelpLink('pc'));
$macContainer->addElement(new htmlOutputText(_('MAC address'), true, true)); $return->addElement($pcContainer);
$macContainer->addElement(new htmlHelpLink('mac')); $macContainer = new htmlTable();
$return->addElement($macContainer); $macContainer->addElement(new htmlOutputText(_('MAC address'), true, true));
$commentContainer = new htmlTable(); $macContainer->addElement(new htmlHelpLink('mac'));
$commentContainer->addElement(new htmlOutputText(_('Description'), true)); $return->addElement($macContainer);
$commentContainer->addElement(new htmlHelpLink('description')); $commentContainer = new htmlTable();
$return->addElement($commentContainer); $commentContainer->addElement(new htmlOutputText(_('Description'), true));
$activeContainer = new htmlTable(); $commentContainer->addElement(new htmlHelpLink('description'));
$activeContainer->colspan = 2; $return->addElement($commentContainer);
$activeContainer->addElement(new htmlOutputText(_('Active'))); $activeContainer = new htmlTable();
$activeContainer->addElement(new htmlHelpLink('active')); $activeContainer->colspan = 2;
$return->addElement($activeContainer, true); $activeContainer->addElement(new htmlOutputText(_('Active')));
// Reset oberlaped ips $activeContainer->addElement(new htmlHelpLink('active'));
$this->reset_overlapd_ip(); $return->addElement($activeContainer, true);
// Reset oberlaped ips
$this->reset_overlapd_ip();
// If $ranges is not a array, then create one: // If $ranges is not a array, then create one:
if (!is_array($this->fixed_ip)) { if (!is_array($this->fixed_ip)) {
$this->fixed_ip = array(); $this->fixed_ip = array();
}
$pcs = array();
foreach($this->fixed_ip AS $id=>$arr) {
// pc name
$pcError = "";
$existsInDifferentDn = $this->hostNameExists($_POST['pc_'.$id]);
if (!$this->processed) {
$pcError = "";
} }
$pcs = array(); elseif (strlen($this->fixed_ip[$id]['cn'])>20) {
foreach($this->fixed_ip AS $id=>$arr) { $pcError = _("The PC name may not be longer than 20 characters.");
// pc name
$pcError = "";
if (!$this->processed) {
$pcError = "";
}
elseif (strlen($this->fixed_ip[$id]['cn'])>20) {
$pcError = _("The PC name may not be longer than 20 characters.");
}
elseif (strlen($this->fixed_ip[$id]['cn'])<2) {
$pcError = _("The PC name needs to be at least 2 characters long.");
}
elseif (in_array($this->fixed_ip[$id]['cn'], $pcs) ) {
$pcError = _("This PC name already exists.");
}
elseif (isset($_POST['pc_'.$id]) && !preg_match("/^[A-Za-z0-9\\._-]*$/", $_POST['pc_'.$id])) {
$pcError = _("The PC name may only contain A-Z, a-z and 0-9.");
}
$pcs[] = $this->fixed_ip[$id]['cn'];
// MAC address
$macError = "";
if (!$this->processed) {
$macError = "";
}
elseif ($this->check_mac($this->fixed_ip[$id]['mac'])) {
$macError = _("Invalid MAC address.");
}
// descripton
$descriptionError = "";
if (!$this->processed) {
$descriptionError = "";
}
elseif (!get_preg($this->fixed_ip[$id]['description'], 'ascii')) {
$descriptionError = _("Invalid description.");
}
// fixed ip
$ipError = "";
if (!$this->processed || ($this->fixed_ip[$id]['ip'] == '')) {
$ipError = "";
}
elseif (!check_ip($this->fixed_ip[$id]['ip'])) {
$ipError = _("The IP address is invalid.");
}
elseif (!range::check_subnet_range($this->fixed_ip[$id]['ip'],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'))) {
$ipError = _("The IP address does not match the subnet.");
}
elseif (!$this->overlapd_ip($this->fixed_ip[$id]['ip'])) {
$ipError = _("The IP address is already in use.");
}
$error = '';
if ($pcError != '') {
$error .= ' ' . $pcError;
}
if ($macError != '') {
$error .= ' ' . $macError;
}
if ($ipError != '') {
$error .= ' ' . $ipError;
}
if ($descriptionError != '') {
$error .= ' ' . $descriptionError;
}
$return->addElement(new htmlInputField('ip_'.$id, $this->fixed_ip[$id]['ip'], 20));
$pcInput = new htmlInputField('pc_'.$id, $this->fixed_ip[$id]['cn'], 20);
if (!empty($autoNames)) {
$pcInput->enableAutocompletion($autoNames);
}
$return->addElement($pcInput);
$return->addElement(new htmlInputField('mac_'.$id, $this->fixed_ip[$id]['mac'], 20));
$return->addElement(new htmlInputField('description_'.$id, $this->fixed_ip[$id]['description'], 20));
$return->addElement(new htmlInputCheckbox('active_'.$id, $this->fixed_ip[$id]['active']));
$return->addElement(new htmlButton('drop_ip_'.$id, 'del.png', true));
$return->addElement(new htmlOutputText($error), true);
} }
$return->addElement(new htmlSpacer(null, '10px'), true); elseif (strlen($this->fixed_ip[$id]['cn'])<2) {
// add host $pcError = _("The PC name needs to be at least 2 characters long.");
$return->addElement(new htmlInputField('ip_add', '', 20)); }
$newPCInput = new htmlInputField('pc_add', '', 20); elseif (in_array($this->fixed_ip[$id]['cn'], $pcs) ) {
$pcError = _("This PC name already exists.");
}
elseif (isset($_POST['pc_'.$id]) && !preg_match("/^[A-Za-z0-9\\._-]*$/", $_POST['pc_'.$id])) {
$pcError = _("The PC name may only contain A-Z, a-z and 0-9.");
}
elseif ($existsInDifferentDn !== false) {
$pcError = sprintf(_('This PC name already exists in %s. Use e.g. %s.'), $existsInDifferentDn[0], $existsInDifferentDn[1]);
}
$pcs[] = $this->fixed_ip[$id]['cn'];
// MAC address
$macError = "";
if (!$this->processed) {
$macError = "";
}
elseif ($this->check_mac($this->fixed_ip[$id]['mac'])) {
$macError = _("Invalid MAC address.");
}
// descripton
$descriptionError = "";
if (!$this->processed) {
$descriptionError = "";
}
elseif (!get_preg($this->fixed_ip[$id]['description'], 'ascii')) {
$descriptionError = _("Invalid description.");
}
// fixed ip
$ipError = "";
if (!$this->processed || ($this->fixed_ip[$id]['ip'] == '')) {
$ipError = "";
}
elseif (!check_ip($this->fixed_ip[$id]['ip'])) {
$ipError = _("The IP address is invalid.");
}
elseif (!range::check_subnet_range($this->fixed_ip[$id]['ip'],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->attributes['cn'][0],
$this->getAccountContainer()->getAccountModule('dhcp_settings')->getDHCPOption('subnet-mask'))) {
$ipError = _("The IP address does not match the subnet.");
}
elseif (!$this->overlapd_ip($this->fixed_ip[$id]['ip'])) {
$ipError = _("The IP address is already in use.");
}
$error = '';
if ($pcError != '') {
$error .= ' ' . $pcError;
}
if ($macError != '') {
$error .= ' ' . $macError;
}
if ($ipError != '') {
$error .= ' ' . $ipError;
}
if ($descriptionError != '') {
$error .= ' ' . $descriptionError;
}
$return->addElement(new htmlInputField('ip_'.$id, $this->fixed_ip[$id]['ip'], 20));
$pcInput = new htmlInputField('pc_'.$id, $this->fixed_ip[$id]['cn'], 20);
if (!empty($autoNames)) { if (!empty($autoNames)) {
$newPCInput->enableAutocompletion($autoNames); $pcInput->enableAutocompletion($autoNames);
} }
$return->addElement($newPCInput); $return->addElement($pcInput);
$return->addElement(new htmlInputField('mac_add', '', 20)); $return->addElement(new htmlInputField('mac_'.$id, $this->fixed_ip[$id]['mac'], 20));
$return->addElement(new htmlInputField('description_add', '', 20)); $return->addElement(new htmlInputField('description_'.$id, $this->fixed_ip[$id]['description'], 20));
$return->addElement(new htmlInputCheckbox('active_add', true)); $return->addElement(new htmlInputCheckbox('active_'.$id, $this->fixed_ip[$id]['active']));
$return->addElement(new htmlButton('add_ip', 'add.png', true), true); $return->addElement(new htmlButton('drop_ip_'.$id, 'del.png', true));
$return->addElement(new htmlOutputText($error), true);
}
$return->addElement(new htmlSpacer(null, '10px'), true);
// add host
$return->addElement(new htmlInputField('ip_add', '', 20));
$newPCInput = new htmlInputField('pc_add', '', 20);
if (!empty($autoNames)) {
$newPCInput->enableAutocompletion($autoNames);
}
$return->addElement($newPCInput);
$return->addElement(new htmlInputField('mac_add', '', 20));
$return->addElement(new htmlInputField('description_add', '', 20));
$return->addElement(new htmlInputCheckbox('active_add', true));
$return->addElement(new htmlButton('add_ip', 'add.png', true), true);
// add existing host entry // add existing host entry
if (!empty($this->hostCache)) { if (!empty($this->hostCache)) {
$return->addVerticalSpace('20px'); $return->addVerticalSpace('20px');
$addHostButton = new htmlAccountPageButton(get_class($this), 'addHost', 'add', _('Add existing host')); $addHostButton = new htmlAccountPageButton(get_class($this), 'addHost', 'add', _('Add existing host'));
$addHostButton->setIconClass('createButton'); $addHostButton->setIconClass('createButton');
$return->addElement($addHostButton , true); $return->addElement($addHostButton , true);
}
} }
return $return; return $return;
} }
/**
* Checks if the given host name already exists.
*
* @param string $name host name
* @return boolean|array false if not exists, DN + new name suggestion if exists
*/
private function hostNameExists($name) {
$this->fillExistingDhcpHosts();
foreach ($this->existingDhcpHostsCache as &$host) {
if ($name === $host['name']) {
$dn = $host['dn'];
if ($this->getAccountContainer()->isNewAccount || strpos($dn, $this->getAccountContainer()->dn_orig) === false) {
return array($dn, $this->getHostNameSuggestion($name));
}
}
}
return false;
}
/**
* Returns a suggestion for a free host name.
*
* @param string $name host name
* @return string suggested new name
*/
private function getHostNameSuggestion($name) {
$matches = array();
$number = 0;
$namePrefix = $name;
if (preg_match('/(.*[^0-9])([0-9]+)/', $name, $matches)) {
$namePrefix = $matches[1];
$number = $matches[2];
}
while (true) {
$number++;
$newName = $namePrefix . $number;
$found = false;
foreach ($this->existingDhcpHostsCache as &$host) {
if ($host['name'] === $newName) {
$found = true;
break;
}
}
if (!$found) {
return $newName;
}
}
}
/** /**
* Returns the HTML meta data for the add host page. * Returns the HTML meta data for the add host page.
* *
@ -869,6 +924,23 @@ class fixed_ip extends baseModule {
return $this->getAccountContainer()->dn_orig == $rootSuffix; return $this->getAccountContainer()->dn_orig == $rootSuffix;
} }
/**
* Fills the list of existing DHCP hosts.
*/
private function fillExistingDhcpHosts() {
if ($this->existingDhcpHostsCache != null) {
return $this->existingDhcpHostsCache;
}
$entries = searchLDAPByAttribute('cn', '*', 'dhcpHost', array('cn'), array('dhcp'));
$this->existingDhcpHostsCache = array();
foreach ($entries as $entry) {
$this->existingDhcpHostsCache[] = array(
'dn' => $entry['dn'],
'name' => $entry['cn'][0]
);
}
}
} }
?> ?>