Code

Added additional information to the extended error message
[gosa.git] / include / class_ldap.inc
index ad98c710bc000e74412c8fdcf86dc01b83bbc6e3..a1f960aa3bc730f67939ee52a170f3530ec83e84 100644 (file)
@@ -2,7 +2,7 @@
 /*****************************************************************************
   newldap.inc - version 1.0
   Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
-  Copyright (C) 2004 Cajus Pollmeier <pollmeier@gonicus.de>
+  Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
 
   Based in code of ldap.inc of
   Copyright (C) 1998  Eric Kilfoil <eric@ipass.net>
@@ -12,7 +12,7 @@ define("ALREADY_EXISTING_ENTRY",-10001);
 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
 define("NO_FILE_UPLOADED",10003);
 define("INSERT_OK",10000);
-define("COLON_OVERRIDE", TRUE);
+define("SPECIALS_OVERRIDE", TRUE);
 
 class LDAP{
 
@@ -30,50 +30,60 @@ class LDAP{
   var $hostname = "";
   var $follow_referral = FALSE;
   var $referrals= array();
+  var $max_ldap_query_time = 0;   // 0, empty or negative values will disable this check 
 
   function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
   {
+    global $config;
     $this->follow_referral= $follow_referral;
     $this->tls=$tls;
     $this->binddn=$this->convert($binddn);
 
     $this->bindpw=$bindpw;
     $this->hostname=$hostname;
+
+    /* Check if MAX_LDAP_QUERY_TIME is defined */ 
+    if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){
+      $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME'];
+      $this->max_ldap_query_time = (float)($str);
+    }
+
     $this->connect();
   }
 
 
+  /* Function to replace all problematic characters inside a DN by \001XX, where
+     \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely
+     that this character is inside a DN.
+     
+     Currently used codes:
+      ,   => CO
+      \2C => CO
+      (   => OB
+      )   => CB
+      /   => SL                                                                  */
   function convert($dn)
   {
-    if (COLON_OVERRIDE == TRUE){
-      $res= preg_replace("/\\\\,/", '###GOSAREPLACED###', $dn);
-      $res= preg_replace("/\\\\2C/", '###GOSAREPLACED###', $res);
-      $res= preg_replace("/\(/", '###OPENBRACE###', $res);
-      $res= preg_replace("/\)/", '###CLOSEBRACE###', $res);
-      $res= preg_replace("/\//", '###SLASH###', $res);
-
-      #if ($dn != $res){
-      #  echo "Conversation from '$dn' to '$res'<br>";
-      #}
-      return ($res);
+    if (SPECIALS_OVERRIDE == TRUE){
+      return (preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
+                           array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
+                           $dn));
     } else {
       return ($dn);
     }
   }
 
 
+  /* Function to fix all problematic characters inside a DN by replacing \001XX
+     codes to their original values. See "convert" for mor information. 
+     ',' characters are always expanded to \, (not \2C), since all tested LDAP
+     servers seem to take it the correct way.                                  */
   function fix($dn)
   {
-    if (COLON_OVERRIDE == TRUE){
-      $res= preg_replace("/###GOSAREPLACED###/", '\,', $dn);
-      $res= preg_replace("/###OPENBRACE###/", '(', $res);
-      $res= preg_replace("/###CLOSEBRACE###/", ')', $res);
-      $res= preg_replace("/###SLASH###/", '/', $res);
-
-      #if ($dn != $res){
-      #  echo "Fix from '$dn' to '$res'<br>";
-      #}
-      return ($res);
+    if (SPECIALS_OVERRIDE == TRUE){
+      return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
+                           array("\,", "(", ")", "/"),
+                           $dn));
     } else {
       return ($dn);
     }
@@ -169,12 +179,23 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
+
+      $start = microtime();
+   
       $this->clearResult();
       $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
-  
+   
+      /* Check if query took longer as specified in max_ldap_query_time */
+      if($this->max_ldap_query_time){
+        $diff = get_MicroTimeDiff($start,microtime());
+        if($diff > $this->max_ldap_query_time){
+          print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
+        }
+      }
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -191,10 +212,22 @@ class LDAP{
         $basedn = $this->basedn;
       else
         $basedn= $this->convert($basedn);
+  
+      $start = microtime();
+
       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
+
+       /* Check if query took longer as specified in max_ldap_query_time */
+      if($this->max_ldap_query_time){
+        $diff = get_MicroTimeDiff($start,microtime());
+        if($diff > $this->max_ldap_query_time){
+          print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
+        }
+      }
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -234,6 +267,7 @@ class LDAP{
 
   function fetch()
   {
+    $att= array();
     if($this->hascon){
       if($this->hasres){
         if ($this->start == 0)
@@ -600,9 +634,13 @@ class LDAP{
     if ($target == $this->basedn){
      return;
     }
-echo "FIXME";
-    $l= array_reverse(explode(",", preg_replace("/,".$this->basedn."/", "", $target)));
+
+    $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
+    $l= array_reverse(ldap_explode_dn($real_path,0));
+    unset($l['count']);
     $cdn= $this->basedn;
+    $tag= "";
+
     foreach ($l as $part){
       $cdn= "$part,$cdn";
 
@@ -623,18 +661,35 @@ echo "FIXME";
       $attrs= $this->fetch();
 
       /* Create missing entry? */
-      if (!count ($attrs)){
+      if (count ($attrs)){
+      
+        /* Catch the tag - if present */
+        if (isset($attrs['gosaUnitTag'][0])){
+          $tag= $attrs['gosaUnitTag'][0];
+        }
+
+      } else {
         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
 
         $na= array();
         switch ($type){
           case 'ou':
-            $na["objectClass"]= "organizationalUnit";
+            if ($tag != ""){
+              $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
+              $na["gosaUnitTag"]= $tag;
+            } else {
+              $na["objectClass"]= "organizationalUnit";
+            }
             $na["ou"]= $param;
             break;
           case 'dc':
-            $na["objectClass"]= array("dcObject", "top", "locality");
+            if ($tag != ""){
+              $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
+              $na["gosaUnitTag"]= $tag;
+            } else {
+              $na["objectClass"]= array("dcObject", "top", "locality");
+            }
             $na["dc"]= $param;
             break;
           default:
@@ -705,7 +760,12 @@ echo "FIXME";
     if ($this->error == 'Success'){
       return $this->error;
     } else {
-      $error= $this->error." (".$this->get_additional_error().")";
+      $adderror= $this->get_additional_error();
+      if ($adderror != ""){
+        $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->base, $this->hostname).")";
+      } else {
+        $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
+      }
       return $error;
     }
   }
@@ -1034,6 +1094,35 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     }
 
   }
+  
+  function get_objectclasses()
+  {
+         $objectclasses = array();
+       
+         # Get base to look for schema 
+         $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
+         $attr = @ldap_get_entries($this->cid,$sr);
+         if (!isset($attr[0]['subschemasubentry'][0])){
+           return array();
+         }
+       
+         # Get list of objectclasses
+         $nb= $attr[0]['subschemasubentry'][0];
+         $objectclasses= array();
+         $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
+         $attrs= ldap_get_entries($this->cid,$sr);
+         if (!isset($attrs[0])){
+           return array();
+         }
+         foreach ($attrs[0]['objectclasses'] as $val){
+           $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
+           if ($name != $val){
+             $objectclasses[$name]= $val;
+           }
+         }
+         
+         return $objectclasses;
+  }
 
 }