Code

Updated translation, fixed some typo/errors
[gosa.git] / include / class_ldap.inc
index 11d42152ba3d6078f60aa9138bf0f80d7a45b587..04294325d4a263b086c1a88c54c05f753b092756 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>
 define("ALREADY_EXISTING_ENTRY",-10001);
 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
 define("NO_FILE_UPLOADED",10003);
-
-
 define("INSERT_OK",10000);
-
-
+define("SPECIALS_OVERRIDE", TRUE);
 
 class LDAP{
 
@@ -33,17 +30,70 @@ 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=$binddn;
+    $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
+      \22 => TO
+      \"  => TO
+      \+  => PL
+      (   => OB
+      )   => CB
+      /   => SL                                                                  */
+  function convert($dn)
+  {
+    if (SPECIALS_OVERRIDE == TRUE){
+      $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//", "/\\\\22/", '/\\\\"/', "/\\\\3D/", "/\\\\2B/", '/\\\\+/'),
+                           array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL", "\001TO", "\001TO", "\001GL", "\001PL", "\001PL"),
+                           $dn);
+      return (preg_replace('/,\s+/', ',', $tmp));
+    } 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 (SPECIALS_OVERRIDE == TRUE){
+      return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/", "/\001TO/", "/\001PL/", "/\001GL/"),
+                           array("\,", "(", ")", "/", '\"', "\+", "="),
+                           $dn));
+    } else {
+      return ($dn);
+    }
+  }
+
+
   function connect()
   {
     $this->hascon=false;
@@ -59,7 +109,7 @@ class LDAP{
       }
 
       $this->error = "No Error";
-      if ($bid = @ldap_bind($this->cid, $this->binddn, $this->bindpw)) {
+      if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
         $this->error = "Success";
         $this->hascon=true;
       } else {
@@ -79,7 +129,7 @@ class LDAP{
   function rebind($ldap, $referral)
   {
     $credentials= $this->get_credentials($referral);
-    if (@ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
+    if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
       $this->error = "Success";
       $this->hascon=true;
       $this->reconnect= true;
@@ -117,26 +167,41 @@ class LDAP{
     if ($dir == "..")
       $this->basedn = $this->getParentDir();
     else
-      $this->basedn = $dir;
+      $this->basedn = $this->convert($dir);
   }
 
   function getParentDir($basedn = "")
   {
     if ($basedn=="")
       $basedn = $this->basedn;
+    else
+      $basedn = $this->convert($this->basedn);
     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
   }
 
   function search($filter, $attrs= array())
   {
-    
     if($this->hascon){
       if ($this->reconnect) $this->connect();
+
+      $start = microtime();
+   
       $this->clearResult();
-      $this->sr = @ldap_search($this->cid, $this->basedn, $filter, $attrs);
+      $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)) ;
+        }
+      }
+
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -144,17 +209,33 @@ class LDAP{
     }
   }
 
-  function ls($filter = "(objectclass=*)", $basedn = "")
+  function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
       $this->clearResult();
       if ($basedn == "")
         $basedn = $this->basedn;
-      $this->sr = @ldap_list($this->cid, $basedn, $filter);
+      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)) ;
+        }
+      }
+
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
+
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -162,16 +243,18 @@ class LDAP{
     }
   }
 
-  function cat($dn)
+  function cat($dn,$attrs= array("*"))
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
+      $start = microtime();
       $this->clearResult();
       $filter = "(objectclass=*)";
-      $this->sr = @ldap_read($this->cid, $dn, $filter);
+      $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -194,6 +277,7 @@ class LDAP{
 
   function fetch()
   {
+    $att= array();
     if($this->hascon){
       if($this->hasres){
         if ($this->start == 0)
@@ -206,7 +290,7 @@ class LDAP{
         if ($this->re)
         {
           $att= @ldap_get_attributes($this->cid, $this->re);
-          $att['dn']= @ldap_get_dn($this->cid, $this->re);
+          $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
         }
         $this->error = @ldap_error($this->cid);
         if (!isset($att)){
@@ -250,8 +334,7 @@ class LDAP{
           $rv = @ldap_get_dn($this->cid, $this->re);
         
           $this->error = @ldap_error($this->cid);
-          $rv= preg_replace("/[ ]*,[ ]*/", ",", $rv);
-          return($rv);
+          return(trim($this->convert($rv)));
            }
       }else{
         $this->error = "Perform a Fetch with no Search";
@@ -287,7 +370,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_del($this->cid, $dn, $attrs);
+      $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -303,7 +386,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_replace($this->cid, $dn, $attrs);
+      $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -316,8 +399,10 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_delete($this->cid, $deletedn);
+      $start= microtime();
+      $r = @ldap_delete($this->cid, $this->fix($deletedn));
       $this->error = @ldap_error($this->cid);
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
       return($r ? $r : 0);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -355,7 +440,7 @@ class LDAP{
       }
       
       /* Finally Delete own Node */
-      $r = @ldap_delete($this->cid, $deletedn);
+      $r = @ldap_delete($this->cid, $this->fix($deletedn));
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -364,13 +449,198 @@ class LDAP{
     }
   }
 
+  /* Copy given attributes and sub-dns with attributes to destination dn 
+  */
+  function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
+  {
+    error_reporting(E_ALL);
+    
+    if($is_first){
+      echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
+    }else{
+      if(preg_match("/^ou=/",$sourcedn)){
+        echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
+      }else{
+        $tmp = split(",",$sourcedn);
+        
+        echo "&nbsp;<b>"._("Object").":</b> ";
+
+        $deststr = @LDAP::fix($destinationdn);
+        if(strlen($deststr) > 96){
+          $deststr = substr($deststr,0,96)."...";
+        }
+
+        echo $deststr."<br>";
+      }
+    }
+
+    flush();
+    
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+
+      /* Save base dn */
+      $basedn= $this->basedn;
+      $delarray= array();
+     
+      /* Check if destination entry already exists */
+      $this->cat($destinationdn);
+
+      if($this->count()){
+        return;
+      }else{
+        
+        $this->clearResult();
+
+        /* Get source entry */
+        $this->cd($basedn);
+        $this->cat($sourcedn);
+        $attr = $this->fetch();
+
+        /* Error while fetching object / attribute abort*/
+        if((!$attr) || (count($attr)) ==0) {
+          echo _("Error while fetching source dn - aborted!");
+          return;
+        }
+  
+        /* check if this is a department */
+        if(in_array("organizationalUnit",$attr['objectClass'])){
+          $attr['dn'] = $this->convert($destinationdn);
+          $this->cd($basedn);
+          $this->create_missing_trees($destinationdn);
+          $this->cd($destinationdn);
+
+          /* If is first entry, append FAIbranch to department entry */
+          if($is_first){
+            $this->cat($destinationdn);
+            $attr= $this->fetch();
+
+            /* Filter unneeded informations */
+            foreach($attr as $key => $value){
+              if(is_numeric($key)) unset($attr[$key]);
+              if(isset($attr[$key]['count'])){
+                if(is_array($attr[$key])){
+                  unset($attr[$key]['count']);
+                }
+              }
+            }
+            
+            unset($attr['count']);
+            unset($attr['dn']);
+
+            /* Add marking attribute */
+            $attr['objectClass'][] = "FAIbranch";
+            
+            /* Add this entry */
+            $this->modify($attr);
+          }
+        }else{
+
+          /* If this is no department */
+          foreach($attr as $key => $value){
+            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
+              $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
+              $ei= ldap_first_entry($this->cid, $sr);
+              if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
+                $attr[$key] = $tmp;
+              }
+            }
+
+            if(is_numeric($key)) unset($attr[$key]);
+            if(isset($attr[$key]['count'])){
+              if(is_array($attr[$key])){
+                unset($attr[$key]['count']);
+              }
+            }
+          }
+          unset($attr['count']);
+          unset($attr['dn']);
+
+          if(!in_array("gosaApplication" , $attr['objectClass'])){
+            if($type=="branch"){
+              $attr['FAIstate'] ="branch";
+            }elseif($type=="freeze"){
+              $attr['FAIstate'] ="freeze";
+            }else{
+              print_red(_("Unknown FAIstate %s"),$type);
+            }
+          }elseif(in_array("gosaApplication",$attr['objectClass'])){
+            if(!in_array("FAIobject",$attr['objectClass'])){
+              $attr['objectClass'][] = "FAIobject";
+            }
+            $attr['FAIstate'] = $type;
+          }
+
+          /* Replace FAIdebianRelease with new release name */
+          if(in_array("FAIpackageList" , $attr['objectClass'])){
+            $attr['FAIdebianRelease'] = $destinationName;
+            if($type=="branch"){
+              $attr['FAIstate'] ="branch";
+            }elseif($type=="freeze"){
+              $attr['FAIstate'] ="freeze";
+            }else{
+              print_red(_("Unknown FAIstate %s"),$type);
+            }
+          }
+
+          /* Add entry */
+          $this->cd($destinationdn);
+          $this->cat($destinationdn);
+          $a = $this->fetch();
+          if(!count($a)){
+            $this->add($attr);
+          }
+
+          if($this->error != "Success"){
+            /* Some error occurred */
+            print "---------------------------------------------";
+            print $this->get_error()."<br>";
+            print $sourcedn."<br>";
+            print $destinationdn."<br>";
+            print_a( $attr);
+            exit();
+          }          
+        }
+      }
+
+      echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
+
+      $this->ls ("(objectClass=*)",$sourcedn);
+      while ($this->fetch()){
+        $deldn= $this->getDN();
+        $delarray[$deldn]= strlen($deldn);
+      }
+      asort ($delarray);
+      reset ($delarray);
+
+       $depth ++;
+      foreach($delarray as $dn => $bla){
+        if($dn != $destinationdn){
+          $this->cd($basedn);
+          $item = $this->fetch($this->cat($dn));
+          if(!in_array("FAIbranch",$item['objectClass'])){
+            $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
+          } 
+        }
+      }
+    }
+    if($is_first){
+      echo "<p class='seperator'>&nbsp;</p>";
+    }
+
+  }
 
   function modify($attrs)
   {
+    if(count($attrs) == 0){
+      return (0);
+    }
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_modify($this->cid, $this->basedn, $attrs);
+      $start= microtime();
+      $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
       return($r ? $r : 0);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -382,8 +652,10 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_add($this->cid, $this->basedn, $attrs);
+      $start= microtime();
+      $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
       return($r ? $r : 0);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -391,14 +663,168 @@ class LDAP{
     }
   }
 
+
   function create_missing_trees($target)
+  {
+    global $config;
+
+    $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
+
+    if ($target == $this->basedn){
+      $l= array("dummy");
+    } else {
+      $l= array_reverse(gosa_ldap_explode_dn($real_path));
+    }
+    unset($l['count']);
+    $cdn= $this->basedn;
+    $tag= "";
+
+    /* Load schema if available... */
+    $classes= $this->get_objectclasses();
+
+    foreach ($l as $part){
+      if ($part != "dummy"){
+        $cdn= "$part,$cdn";
+      }
+
+      /* Ignore referrals */
+      $found= false;
+      foreach($this->referrals as $ref){
+        $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
+        if ($base == $cdn){
+          $found= true;
+          break;
+        }
+      }
+      if ($found){
+        continue;
+      }
+
+      $this->cat ($cdn);
+      $attrs= $this->fetch();
+
+      /* Create missing entry? */
+      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();
+
+        /* Automatic or traditional? */
+        if(count($classes)){
+
+          /* Get name of first matching objectClass */
+          $ocname= "";
+          foreach($classes as $class){
+            if (isset($class['MUST']) && $class['MUST'] == "$type"){
+
+              /* Look for first classes that is structural... */
+              if (isset($class['STRUCTURAL'])){
+                $ocname= $class['NAME'];
+                break;
+              }
+
+              /* Look for classes that are auxiliary... */
+              if (isset($class['AUXILIARY'])){
+                $ocname= $class['NAME'];
+              }
+            }
+          }
+
+          /* Bail out, if we've nothing to do... */
+          if ($ocname == ""){
+            print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
+            echo $_SESSION['errors'];
+            exit;
+          }
+
+          /* Assemble_entry */
+          if ($tag != ""){
+            $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
+          } else {
+            $na['objectClass']= array($ocname);
+          }
+          if (isset($classes[$ocname]['AUXILIARY'])){
+            $na['objectClass'][]= $classes[$ocname]['SUP'];
+          }
+          if ($type == "dc"){
+            /* This is bad actually, but - tell me a better way? */
+            $na['objectClass'][]= 'locality';
+          }
+          $na[$type]= $param;
+          if (is_array($classes[$ocname]['MUST'])){
+            foreach($classes[$ocname]['MUST'] as $attr){
+              $na[$attr]= "filled";
+            }
+          }
+
+        } else {
+
+          /* Use alternative add... */
+          switch ($type){
+            case 'ou':
+              if ($tag != ""){
+                $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
+                $na["gosaUnitTag"]= $tag;
+              } else {
+                $na["objectClass"]= "organizationalUnit";
+              }
+              $na["ou"]= $param;
+              break;
+            case 'dc':
+              if ($tag != ""){
+                $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
+                $na["gosaUnitTag"]= $tag;
+              } else {
+                $na["objectClass"]= array("dcObject", "top", "locality");
+              }
+              $na["dc"]= $param;
+              break;
+            default:
+              print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
+              echo $_SESSION['errors'];
+              exit;
+          }
+
+        }
+        $this->cd($cdn);
+        $this->add($na);
+        show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
+        if (!preg_match('/success/i', $this->error)){
+          return FALSE;
+        }
+      }
+    }
+
+    return TRUE;
+  }
+
+
+  function create_missing_trees_old($target)
   {
     /* Ignore create_missing trees if the base equals target */
     if ($target == $this->basedn){
      return;
     }
-    $l= array_reverse(explode(",", preg_replace("/,".$this->basedn."/", "", $target)));
+
+    $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
+    $tmp = ldap_explode_dn($real_path,0);
+    if(!$tmp){
+      print_red(sprintf(_("The referral url '%s' is missing the ldap base. It should look like this 'ldap://server:port/base'."),$this->fix($this->basedn)));
+      return;
+    }
+
+    $l= array_reverse($tmp);
+    unset($l['count']);
     $cdn= $this->basedn;
+    $tag= "";
+
     foreach ($l as $part){
       $cdn= "$part,$cdn";
 
@@ -419,18 +845,35 @@ class LDAP{
       $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:
@@ -467,7 +910,7 @@ class LDAP{
   {
     $data= "";
     if ($this->reconnect) $this->connect();
-    $sr= @ldap_read($this->cid, $dn, "objectClass=*", array("$name"));
+    $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
 
     /* fill data from LDAP */
     if ($sr) {
@@ -483,8 +926,8 @@ class LDAP{
     return ($data);
     else
     return ($info);
-       
-       
+  
+  
   }
  
 
@@ -501,7 +944,12 @@ class LDAP{
     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->basedn, $this->hostname).")";
+      } else {
+        $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
+      }
       return $error;
     }
   }
@@ -519,7 +967,7 @@ class LDAP{
     if (isset($referrals[$server])){
       return ($referrals[$server]);
     } else {
-      $ret['ADMIN']= $this->binddn;
+      $ret['ADMIN']= $this->fix($this->binddn);
       $ret['PASSWORD']= $this->bindpw;
     }
 
@@ -551,15 +999,17 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
 
       $this->cd($dn);
       $this->search("$filter");
-       $i=0;
+
+      $i=0;
       while ($attrs= $this->fetch()){
-       $j=0;
-       foreach ($attributes as $at)
-        {
-       
-       $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
-       $j++;}
-       $i++;
+        $j=0;
+
+        foreach ($attributes as $at){
+          $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
+          $j++;
+        }
+
+        $i++;
       }
 
     return ($display);
@@ -575,9 +1025,9 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     }
 
     /* Searching Ldap Tree */
-    $sr= @ldap_read($this->cid, $dn, $filter, $name);
+    $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
 
-    /* Get the first entry */          
+    /* Get the first entry */   
     $entry= @ldap_first_entry($this->cid, $sr);
 
     /* Get all attributes related to that Objekt */
@@ -589,7 +1039,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
 
     /* Reset index */
     $i = 1 ; 
-       $identifier = array();
+  $identifier = array();
     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
     while ($attribute) {
       $i++;
@@ -619,7 +1069,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
 
   function dn_exists($dn)
   {
-    return @ldap_list($this->cid, $dn, "(objectClass=*)", array("objectClass"));
+    return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
   }
   
 
@@ -687,7 +1137,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
       $ndn = split("#", $lineone[0]);
       $line = $ndn[1];
 
-      $dnn = split (":",$line);
+      $dnn = split (":",$line,2);
       $current_line = $ndn[0];
       $dn    = $dnn[0];
       $value = $dnn[1];
@@ -756,7 +1206,7 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
         }
 
         /* Split the line into  attribute  and value */
-        $attr   = split(":", $row);
+        $attr   = split(":", $row,2);
         $attr[0]= trim($attr[0]);  /* attribute */
         $attr[1]= trim($attr[1]);  /* value */
 
@@ -828,6 +1278,178 @@ function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $rec
     }
 
   }
+  
+  function get_objectclasses_old()
+  {
+    $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])){
+      $this->error  = @ldap_error($this->cid);
+      gosa_log($this->get_error());
+      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;
+  }
+
+
+  function get_objectclasses()
+  {
+    global $config;
+    $objectclasses = array();
+
+    if(isset($config) && preg_match("/config/i",get_class($config))){
+      if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
+        return($objectclasses);
+      }
+    }
+
+# Get base to look for schema
+    $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
+    if(!$sr){
+      $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
+    }
+
+    $attr = @ldap_get_entries($this->cid,$sr);
+    if (!isset($attr[0]['subschemasubentry'][0])){
+      return array();
+    }
+
+    /* Get list of objectclasses and fill array */
+    $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){
+      if (preg_match('/^[0-9]+$/', $val)){
+        continue;
+      }
+      $name= "OID";
+      $pattern= split(' ', $val);
+      $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
+      $objectclasses[$ocname]= array();
+
+      foreach($pattern as $chunk){
+        switch($chunk){
+
+          case '(':
+            $value= "";
+            break;
+
+          case ')': if ($name != ""){
+                      $objectclasses[$ocname][$name]= $this->value2container($value);
+                    }
+                    $name= "";
+                    $value= "";
+                    break;
+
+          case 'NAME':
+          case 'DESC':
+          case 'SUP':
+          case 'STRUCTURAL':
+          case 'ABSTRACT':
+          case 'AUXILIARY':
+          case 'MUST':
+          case 'MAY':
+                    if ($name != ""){
+                      $objectclasses[$ocname][$name]= $this->value2container($value);
+                    }
+                    $name= $chunk;
+                    $value= "";
+                    break;
+
+          default:  $value.= $chunk." ";
+        }
+      }
+
+    }
+
+    return $objectclasses;
+  }
+
+  function value2container($value)
+  {
+    /* Set emtpy values to "true" only */
+    if (preg_match('/^\s*$/', $value)){
+      return true;
+    }
+
+    /* Remove ' and " if needed */
+    $value= preg_replace('/^[\'"]/', '', $value);
+    $value= preg_replace('/[\'"] *$/', '', $value);
+
+    /* Convert to array if $ is inside... */
+    if (preg_match('/\$/', $value)){
+      $container= preg_split('/\s*\$\s*/', $value);
+    } else {
+      $container= chop($value);
+    }
+
+    return ($container);
+  }
+
+  function log($string)
+  {
+    if (isset($_SESSION['config'])){
+      $cfg= $_SESSION['config'];
+      if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
+        syslog (LOG_INFO, $string);
+      }
+    }
+  }
+  
+  /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
+  function getCn($dn){
+    $simple= split(",", $dn);
+
+    foreach($simple as $piece) {
+      $partial= split("=", $piece);
+
+      if($partial[0] == "cn"){
+        return $partial[1];
+      }
+    }
+
+  }
+
+  function get_naming_contexts($server, $admin= "", $password= "")
+  {
+    /* Build LDAP connection */
+    $ds= ldap_connect ($server);
+    if (!$ds) {
+      die ("Can't bind to LDAP. No check possible!");
+    }
+    ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+    $r= ldap_bind ($ds, $admin, $password);
+
+    /* Get base to look for naming contexts */
+    $sr  = @ldap_read ($ds, "", "objectClass=*", array("+"));
+    $attr= @ldap_get_entries($ds,$sr);
+
+    return ($attr[0]['namingcontexts']);
+  }
 
 }