From d8609c1819deb731ec7d821113870c45ef2db015 Mon Sep 17 00:00:00 2001 From: cajus Date: Mon, 5 Oct 2009 11:27:37 +0000 Subject: [PATCH] Added allocation algorithms git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@14509 594d385d-05f5-0310-b6e9-bd551577e9d8 --- gosa-core/contrib/gosa.conf.5 | 39 +++- gosa-core/include/class_ldap.inc | 18 +- gosa-core/include/functions.inc | 168 ++++++++++++++++++ .../admin/groups/class_groupGeneric.inc | 41 +---- .../personal/posix/class_posixAccount.inc | 90 +--------- 5 files changed, 228 insertions(+), 128 deletions(-) diff --git a/gosa-core/contrib/gosa.conf.5 b/gosa-core/contrib/gosa.conf.5 index da8283fb7..185c9efc6 100644 --- a/gosa-core/contrib/gosa.conf.5 +++ b/gosa-core/contrib/gosa.conf.5 @@ -923,13 +923,50 @@ can even be dynamic. Take a look at the definition below. .PP +.B idAllocationMethod +.I traditional/pool +.PP +The +.I idAllocationMethod +statement defines how GOsa generates numeric user and group id values. If it is set to +.I traditional +GOsa will do create a lock and perform a search for the next free ID. The lock will be +removed after the procedure completes. +.I pool +will use the sambaUnixIdPool objectclass settings inside your LDAP. This one is unsafe, +because it does not check for concurrent LDAP access and already used IDs in this range. +On the other hand it is much faster. +.PP + .B minId .I integer .PP The .I minId statement defines the minimum assignable user or group id to avoid security leaks with -uid 0 accounts. +uid 0 accounts. This is used for the +.I traditional +method +.PP + +.B uidPoolMin/gidPoolMin +.I integer +.PP +The +.I uidPoolMin/gidPoolMin +statement defines the minimum assignable user/group id for use with the +.I pool +method. +.PP + +.B uidPoolMax/gidPoolMax +.I integer +.PP +The +.I uidPoolMin/gidPoolMin +statement defines the highest assignable user/group id for use with the +.I pool +method. .PP .B nextIdHook diff --git a/gosa-core/include/class_ldap.inc b/gosa-core/include/class_ldap.inc index 29f82e7fc..3bcf7f410 100644 --- a/gosa-core/include/class_ldap.inc +++ b/gosa-core/include/class_ldap.inc @@ -418,7 +418,23 @@ class LDAP{ if ($dn == "") $dn = $this->basedn; - $r = @ldap_mod_del($this->cid, LDAP::fix($dn), $attrs); + $r = ldap_mod_del($this->cid, LDAP::fix($dn), $attrs); + $this->error = @ldap_error($this->cid); + return($r); + }else{ + $this->error = "Could not connect to LDAP server"; + return(""); + } + } + + function mod_add($attrs = "", $dn = "") + { + if($this->hascon){ + if ($this->reconnect) $this->connect(); + if ($dn == "") + $dn = $this->basedn; + + $r = @ldap_mod_add($this->cid, LDAP::fix($dn), $attrs); $this->error = @ldap_error($this->cid); return($r); }else{ diff --git a/gosa-core/include/functions.inc b/gosa-core/include/functions.inc index c09a59acf..48bf1b871 100644 --- a/gosa-core/include/functions.inc +++ b/gosa-core/include/functions.inc @@ -2829,5 +2829,173 @@ function isIpInNet($ip, $net, $mask) { } +function get_next_id($attrib, $dn) +{ + global $config; + + switch ($config->get_cfg_value("idAllocationMethod", "traditional")){ + case "pool": + return get_next_id_pool($attrib); + case "traditional": + return get_next_id_traditional($attrib, $dn); + } + + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." "._("unknown idAllocation method!"), ERROR_DIALOG); + return null; +} + + +function get_next_id_pool($attrib) { + global $config; + + /* Fill informational values */ + $min= $config->get_cfg_value("${attrib}PoolMin", 10000); + $max= $config->get_cfg_value("${attrib}PoolMax", 40000); + + /* Sanity check */ + if ($min >= $max) { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." ".sprintf(_("%sPoolMin >= %sPoolMax!"), $attrib), ERROR_DIALOG); + return null; + } + + /* ID to skip */ + $ldap= $config->get_ldap_link(); + $id= null; + + /* Try to allocate the ID several times before failing */ + $tries= 3; + while ($tries--) { + + /* Look for ID map entry */ + $ldap->cd ($config->current['BASE']); + $ldap->search ("(&(objectClass=sambaUnixIdPool)($attrib=*))", array("$attrib")); + + /* If it does not exist, create one with these defaults */ + if ($ldap->count() == 0) { + /* Fill informational values */ + $minUserId= $config->get_cfg_value("uidPoolMin", 10000); + $minGroupId= $config->get_cfg_value("gidPoolMin", 10000); + + /* Add as default */ + $attrs= array("objectClass" => array("organizationalUnit", "sambaUnixIdPool")); + $attrs["ou"]= "idmap"; + $attrs["uidNumber"]= $minUserId; + $attrs["gidNumber"]= $minGroupId; + $ldap->cd("ou=idmap,".$config->current['BASE']); + $ldap->add($attrs); + if ($ldap->error != "Success") { + msg_dialog::display(_("Error"), _("Cannot create sambaUnixIdPool entry!"), ERROR_DIALOG); + return null; + } + $tries++; + continue; + } + /* Bail out if it's not unique */ + if ($ldap->count() != 1) { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." "._("sambaUnixIdPool is not unique!"), ERROR_DIALOG); + return null; + } + + /* Store old attrib and generate new */ + $attrs= $ldap->fetch(); + $dn= $ldap->getDN(); + $oldAttr= $attrs[$attrib][0]; + $newAttr= $oldAttr + 1; + + /* Sanity check */ + if ($newAttr >= $max) { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." "._("no ID available!"), ERROR_DIALOG); + return null; + } + if ($newAttr < $min) { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." "._("no ID available!"), ERROR_DIALOG); + return null; + } + + #FIXME: PHP is not able to do a modification of "del: .../add: ...", so this + # is completely unsafe in the moment. + #/* Remove old attr, add new attr */ + #$attrs= array($attrib => $oldAttr); + #$ldap->rm($attrs, $dn); + #if ($ldap->error != "Success") { + # continue; + #} + $ldap->cd($dn); + $ldap->modify(array($attrib => $newAttr)); + if ($ldap->error != "Success") { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." ".$ldap->get_error(), ERROR_DIALOG); + return null; + } else { + return $newAttr; + } + } + + /* Bail out if we had problems getting the next id */ + if (!$tries) { + msg_dialog::display(_("Error"), _("Cannot allocate a free ID:")." "._("maximum tries exceeded!"), ERROR_DIALOG); + } + + return $id; +} + +function get_next_id_traditional($attrib, $dn) +{ + global $config; + + $ids= array(); + $ldap= $config->get_ldap_link(); + + $ldap->cd ($config->current['BASE']); + if (preg_match('/gidNumber/i', $attrib)){ + $oc= "posixGroup"; + } else { + $oc= "posixAccount"; + } + $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib")); + + /* Get list of ids */ + while ($attrs= $ldap->fetch()){ + $ids[]= (int)$attrs["$attrib"][0]; + } + + /* Add the nobody id */ + $ids[]= 65534; + + /* get the ranges */ + $tmp = array('0'=> 1000); + if (preg_match('/posixAccount/', $oc) && $config->get_cfg_value("uidNumberBase") != ""){ + $tmp= split('-',$config->get_cfg_value("uidNumberBase")); + } elseif($config->get_cfg_value("gidNumberBase") != ""){ + $tmp= split('-',$config->get_cfg_value("gidNumberBase")); + } + + /* Set hwm to max if not set - for backward compatibility */ + $lwm= $tmp[0]; + if (isset($tmp[1])){ + $hwm= $tmp[1]; + } else { + $hwm= pow(2,32); + } + /* Find out next free id near to UID_BASE */ + if ($config->get_cfg_value("baseIdHook") == ""){ + $base= $lwm; + } else { + /* Call base hook */ + $base= get_base_from_hook($dn, $attrib); + } + for ($id= $base; $id++; $id < pow(2,32)){ + if (!in_array($id, $ids)){ + return ($id); + } + } + + /* Should not happen */ + if ($id == $hwm){ + msg_dialog::display(_("Error"), _("Cannot allocate a free ID!"), ERROR_DIALOG); + exit; + } +} + + // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> diff --git a/gosa-core/plugins/admin/groups/class_groupGeneric.inc b/gosa-core/plugins/admin/groups/class_groupGeneric.inc index 0cf314a07..5c9e62da6 100644 --- a/gosa-core/plugins/admin/groups/class_groupGeneric.inc +++ b/gosa-core/plugins/admin/groups/class_groupGeneric.inc @@ -913,7 +913,7 @@ class group extends plugin } } add_lock ("gidnumber", "gosa"); - $this->gidNumber= $this->get_next_id("gidNumber", $this->dn); + $this->gidNumber= get_next_id("gidNumber", $this->dn); } } @@ -1203,45 +1203,6 @@ class group extends plugin return ($message); } - function get_next_id($attrib, $dn) - { - $ids= array(); - $ldap= $this->config->get_ldap_link(); - - $ldap->cd ($this->config->current['BASE']); - if (preg_match('/gidNumber/i', $attrib)){ - $oc= "posixGroup"; - $att= "gidNumberBase"; - } else { - $oc= "posixAccount"; - $att= "uidNumberBase"; - } - $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib")); - - /* Get list of ids */ - while ($attrs= $ldap->fetch()){ - $ids[]= (int)$attrs["$attrib"][0]; - } - - /* Find out next free id near to UID_BASE */ - if ($this->config->get_cfg_value("baseIdHook") == ""){ - $base= $this->config->get_cfg_value($att); - } else { - /* Call base hook */ - $base= get_base_from_hook($dn, $attrib); - } - for ($id= $base; $id++; $id < pow(2,32)){ - if (!in_array($id, $ids)){ - return ($id); - } - } - - /* Check if id reached maximum */ - if ($id >= pow(2,32)){ - msg_dialog::display(_("Error"), _("Cannot allocate a free ID!"), ERROR_DIALOG); - exit; - } - } function getCopyDialog() { diff --git a/gosa-core/plugins/personal/posix/class_posixAccount.inc b/gosa-core/plugins/personal/posix/class_posixAccount.inc index 1ea0509e9..ccb54c03e 100644 --- a/gosa-core/plugins/personal/posix/class_posixAccount.inc +++ b/gosa-core/plugins/personal/posix/class_posixAccount.inc @@ -863,7 +863,7 @@ class posixAccount extends plugin } } add_lock ("uidnumber", "gosa"); - $this->uidNumber= $this->get_next_id("uidNumber", $this->dn); + $this->uidNumber= get_next_id("uidNumber", $this->dn); } } @@ -896,7 +896,7 @@ class posixAccount extends plugin /* Request a new and uniqe gidNumber, if required */ if(!$this->force_ids){ - $this->gidNumber= $this->get_next_id("gidNumber", $this->dn); + $this->gidNumber= get_next_id("gidNumber", $this->dn); }else{ /* If forced gidNumber could not be found, then check if the given group name already exists @@ -1361,88 +1361,6 @@ class posixAccount extends plugin } - function get_next_id_new($attrib, $dn) - { - /* ID to skip */ - $nobody= 65534; - - # again: - # Look for ID map entry (objectClass=sambaUnixIdPool) - - # If it does not exist, create one with these defaults - #dn: ou=idmap,$BASE - #objectClass: organizationalUnit - #objectClass: sambaUnixIdPool - #ou: idmap - #uidNumber: $minId - #gidNumber: $minId - - # Take $attrib, modify it to [$attrib] + 1 - # -> if $attrib does not exist -> bail out - # -> if this works, return [$attrib] - # -> if this does not work: goto again for max 3 times - # -> if this fails -> bail out - } - - - function get_next_id($attrib, $dn) - { - $ids= array(); - $ldap= $this->config->get_ldap_link(); - - $ldap->cd ($this->config->current['BASE']); - if (preg_match('/gidNumber/i', $attrib)){ - $oc= "posixGroup"; - } else { - $oc= "posixAccount"; - } - $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib")); - - /* Get list of ids */ - while ($attrs= $ldap->fetch()){ - $ids[]= (int)$attrs["$attrib"][0]; - } - - /* Add the nobody id */ - $ids[]= 65534; - - /* get the ranges */ - $tmp = array('0'=> 1000); - if (preg_match('/posixAccount/', $oc) && $this->config->get_cfg_value("uidNumberBase") != ""){ - $tmp= split('-',$this->config->get_cfg_value("uidNumberBase")); - } elseif($this->config->get_cfg_value("gidNumberBase") != ""){ - $tmp= split('-',$this->config->get_cfg_value("gidNumberBase")); - } - - /* Set hwm to max if not set - for backward compatibility */ - $lwm= $tmp[0]; - if (isset($tmp[1])){ - $hwm= $tmp[1]; - } else { - $hwm= pow(2,32); - } - - /* Find out next free id near to UID_BASE */ - if ($this->config->get_cfg_value("baseIdHook") == ""){ - $base= $lwm; - } else { - /* Call base hook */ - $base= get_base_from_hook($dn, $attrib); - } - for ($id= $base; $id++; $id < pow(2,32)){ - if (!in_array($id, $ids)){ - return ($id); - } - } - - /* Should not happen */ - if ($id == $hwm){ - msg_dialog::display(_("Error"), _("Cannot allocate a free ID!"), ERROR_DIALOG); - exit; - } - } - - function reload() { /* Set base for all searches */ @@ -1607,9 +1525,9 @@ class posixAccount extends plugin /* Avoid using the same gid/uid number as source user empty numbers to enforce new ones. */ -# $this->savedUidNumber = $this->get_next_id("uidNumber", $this->dn); +# $this->savedUidNumber = $get_next_id("uidNumber", $this->dn); $this->savedUidNumber = ""; -# $this->savedGidNumber = $this->get_next_id("gidNumber", $this->dn); +# $this->savedGidNumber = $get_next_id("gidNumber", $this->dn); $this->savedGidNumber = ""; /* Get group membership */ -- 2.30.2