Code

Added allocation algorithms
authorcajus <cajus@594d385d-05f5-0310-b6e9-bd551577e9d8>
Mon, 5 Oct 2009 11:27:37 +0000 (11:27 +0000)
committercajus <cajus@594d385d-05f5-0310-b6e9-bd551577e9d8>
Mon, 5 Oct 2009 11:27:37 +0000 (11:27 +0000)
git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@14509 594d385d-05f5-0310-b6e9-bd551577e9d8

gosa-core/contrib/gosa.conf.5
gosa-core/include/class_ldap.inc
gosa-core/include/functions.inc
gosa-core/plugins/admin/groups/class_groupGeneric.inc
gosa-core/plugins/personal/posix/class_posixAccount.inc

index da8283fb786026841a8662bf22ba3f8f50ae5e66..185c9efc6f718947be695b1441e341d5d3449ca3 100644 (file)
@@ -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
index 29f82e7fcd4e460a4c7f41dc04c0aa81695cb9b6..3bcf7f410dca6fad7a1bee1610ebda6c0eaccfa1 100644 (file)
@@ -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{
index c09a59acf896815a5d55d8a12754e2fd47275bef..48bf1b87130c5f83763b4f82ae0f0cff25651520 100644 (file)
@@ -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:
 ?>
index 0cf314a07203b693983543b205635f2de7bd62c1..5c9e62da6a87754a386127479926b361e153d434 100644 (file)
@@ -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()
   {
index 1ea0509e950cdbf38401676fd65b663a07ecb60d..ccb54c03ee71be7eb17bca17611cd8b7a0f4c2d3 100644 (file)
@@ -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 */