Code

Udpated Log and Copy&Paste
[gosa.git] / include / class_ldap.inc
index 494b1da9bdad8f4f10098dd5d68d2a7479fee269..126aabbad27a562be5207cd82998a291f78e8399 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*****************************************************************************
   newldap.inc - version 1.0
-  Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
+  Copyright (C) 2003 Alejandro Escanero Blanco <aescanero@chaosdimension.org>
   Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
 
   Based in code of ldap.inc of
@@ -197,6 +197,7 @@ class LDAP{
         }
       }
 
+      $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";
@@ -229,6 +230,8 @@ class LDAP{
         }
       }
 
+      $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";
@@ -281,7 +284,7 @@ class LDAP{
         if ($this->re)
         {
           $att= @ldap_get_attributes($this->cid, $this->re);
-          $att['dn']= $this->convert(@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)){
@@ -325,7 +328,7 @@ class LDAP{
           $rv = @ldap_get_dn($this->cid, $this->re);
         
           $this->error = @ldap_error($this->cid);
-          return($this->convert($rv));
+          return(trim($this->convert($rv)));
            }
       }else{
         $this->error = "Perform a Fetch with no Search";
@@ -527,7 +530,7 @@ class LDAP{
 
           /* If this is no department */
           foreach($attr as $key => $value){
-            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
+            if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
               $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)){
@@ -545,7 +548,8 @@ class LDAP{
           unset($attr['count']);
           unset($attr['dn']);
 
-          if(!in_array("gosaApplication" , $attr['objectClass'])){
+          if((!in_array("gosaApplication" , $attr['objectClass'])) && (!in_array("gotoMimeType", $attr['objectClass']))){
+            $attr['FAIdebianRelease'] = $destinationName;
             if($type=="branch"){
               $attr['FAIstate'] ="branch";
             }elseif($type=="freeze"){
@@ -580,6 +584,8 @@ class LDAP{
         }
       }
 
+      echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
+
       $this->ls ("(objectClass=*)",$sourcedn);
       while ($this->fetch()){
         $deldn= $this->getDN();
@@ -636,19 +642,26 @@ class LDAP{
 
   function create_missing_trees($target)
   {
-    /* Ignore create_missing trees if the base equals target */
-    if ($target == $this->basedn){
-     return;
-    }
+    global $config;
 
     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
-    $l= array_reverse(ldap_explode_dn($real_path,0));
+
+    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){
-      $cdn= "$part,$cdn";
+      if ($part != "dummy"){
+        $cdn= "$part,$cdn";
+      }
 
       /* Ignore referrals */
       $found= false;
@@ -679,36 +692,97 @@ class LDAP{
         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
 
         $na= array();
-        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");
+
+        /* 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'];
+              }
             }
-            $na["dc"]= $param;
-            break;
-          default:
-            print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
+          }
+
+          /* 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 recursive_remove()
   {
     $delarray= array();
@@ -823,7 +897,7 @@ class LDAP{
 
   function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
   {
-    $display= "";
+    $display= array();
 
       $this->cd($dn);
       $this->search("$filter");
@@ -902,7 +976,14 @@ class LDAP{
   
 
 
-  function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
+  /*  This funktion imports ldifs 
+        
+      If DeleteOldEntries is true, the destination entry will be deleted first. 
+      If JustModify is true the destination entry will only be touched by the attributes specified in the ldif.
+      if JustMofify id false the destination dn will be overwritten by the new ldif. 
+    */
+
+  function import_complete_ldif($str_attr,&$error,$JustModify,$DeleteOldEntries)
   {
     if($this->reconnect) $this->connect();
 
@@ -914,8 +995,21 @@ class LDAP{
     $cnt = 0; 
     $current_line = 0;
 
+    /* FIX ldif */
+    $last = "";
+    $tmp  = "";
+    $i = 0;
+    foreach($entries as $entry){
+      if(preg_match("/^ /",$entry)){
+        $tmp[$i] .= trim($entry);
+      }else{
+        $i ++;
+        $tmp[$i] = trim($entry);
+      }
+    }
+
     /* Every single line ... */
-    foreach($entries as $entry) {
+    foreach($tmp as $entry) {
       $current_line ++;
 
       /* Removing Spaces to .. 
@@ -965,7 +1059,7 @@ class LDAP{
       $ndn = split("#", $lineone[0]);
       $line = base64_decode($ndn[1]);
 
-      $dnn = split (":",$line);
+      $dnn = split (":",$line,2);
       $current_line = $ndn[0];
       $dn    = $dnn[0];
       $value = $dnn[1];
@@ -982,18 +1076,18 @@ class LDAP{
       /* Delete before insert */
       $usermdir= false;
     
-      /* The dn address already exists! */
-      if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
+      /* The dn address already exists, Don't delete destination entry, overwrite it */
+      if (($this->dn_exists($value))&&((!$JustModify)&&(!$DeleteOldEntries))) {
 
-        $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
-        return ALREADY_EXISTING_ENTRY;   
+        $usermdir = $usemodify = false;
 
-      } elseif(($this->dn_exists($value))&&($cleanup)){
+      /* Delete old entry first, then add new */
+      } elseif(($this->dn_exists($value))&&($DeleteOldEntries)){
 
         /* Delete first, then add */
         $usermdir = true;        
 
-      } elseif(($this->dn_exists($value))&&($overwrite)) {
+      } elseif(($this->dn_exists($value))&&($JustModify)) {
         
         /* Modify instead of Add */
         $usemodify = true;
@@ -1010,7 +1104,11 @@ class LDAP{
   }
 
 
-  /* Imports a single entry */
+  /* Imports a single entry 
+      If $delete is true;  The old entry will be deleted if it exists.
+      if $modify is true;  All variables that are not touched by the new ldif will be kept.
+      if $modify is false; The new ldif overwrites the old entry, and all untouched attributes get lost.
+  */
   function import_single_entry($str_attr,$modify,$delete)
   {
     if($this->reconnect) $this->connect();
@@ -1034,9 +1132,17 @@ class LDAP{
         }
 
         /* 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 */
+        $attr[1]= $attr[1];  /* value */
+
+        /* Check :: was used to indicate base64_encoded strings */
+        if($attr[1][0] == ":"){
+          $attr[1]=trim(preg_replace("/^:/","",$attr[1]));
+          $attr[1]=base64_decode($attr[1]);
+        }
+
+        $attr[1] = trim($attr[1]);
 
         /* Check for attributes that are used more than once */
         if(!isset($data[$attr[0]])) {
@@ -1061,6 +1167,17 @@ class LDAP{
 
     /* If dn is an index of data, we should try to insert the data */
     if(isset($data['dn'])) {
+
+      /* Fix dn */
+      $tmp = gosa_ldap_explode_dn($data['dn']);
+      unset($tmp['count']);
+      $newdn ="";
+      foreach($tmp as $tm){
+        $newdn.= trim($tm).",";
+      }
+      $newdn = preg_replace("/,$/","",$newdn);
+      $data['dn'] = $newdn;
+   
       /* Creating Entry */
       $this->cd($data['dn']);
 
@@ -1068,19 +1185,45 @@ class LDAP{
       if($delete){
         $this->rmdir_recursive($data['dn']);
       }
-      
+     
       /* Create missing trees */
+      $this->cd ($this->basedn);
       $this->create_missing_trees($data['dn']);
+      $this->cd($data['dn']);
+
+      $dn = $data['dn'];
       unset($data['dn']);
       
-      /* If entry exists use modify */
       if(!$modify){
-        $ret = $this->add($data);
+
+        $this->cat($dn);
+        if($this->count()){
+        
+          /* The destination entry exists, overwrite it with the new entry */
+          $attrs = $this->fetch();
+          foreach($attrs as $name => $value ){
+            if(!is_numeric($name)){
+              if(in_array($name,array("dn","count"))) continue;
+              if(!isset($data[$name])){
+                $data[$name] = array();
+              }
+            }
+          }
+          $ret = $this->modify($data);
+    
+        }else{
+    
+          /* The destination entry doesn't exists, create it */
+          $ret = $this->add($data);
+        }
+
       } else {
+        
+        /* Keep all vars that aren't touched by this ldif */
         $ret = $this->modify($data);
       }
     }
-    show_ldap_error($this->get_error(),_("Ldap import failed"));
+    show_ldap_error($this->get_error(), sprintf(_("Ldap import with dn '%s' failed."),$dn));
     return($ret);
   }
 
@@ -1109,16 +1252,20 @@ class LDAP{
   
   function get_objectclasses()
   {
-         $objectclasses = array();
+    $objectclasses = array();
        
          # 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
+         /* Get list of objectclasses and fill array */
          $nb= $attr[0]['subschemasubentry'][0];
          $objectclasses= array();
          $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
@@ -1127,15 +1274,146 @@ class LDAP{
            return array();
          }
          foreach ($attrs[0]['objectclasses'] as $val){
-           $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
-           if ($name != $val){
-             $objectclasses[$name]= $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']);
+  }
+
+
+  function get_root_dse($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 empty array, if nothing was set */
+    if (!isset($attr[0])){
+      return array();
+    }
+
+    /* Rework array... */
+    $result= array();
+    for ($i= 0; $i<$attr[0]['count']; $i++){
+      $result[$attr[0][$i]]= $attr[0][$attr[0][$i]];
+      unset($result[$attr[0][$i]]['count']);
+    }
+
+    return ($result);
+  }
+
+
 }
 
 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: