Code

Updated comments in heimdal plugin
[gosa.git] / include / class_ldap.inc
index 1e086ecb5b2486cc7f47ece760c23cccc8c01dcb..1973c820b5a408931b378533829a10d632d1f16b 100644 (file)
@@ -37,7 +37,7 @@ class LDAP{
     global $config;
     $this->follow_referral= $follow_referral;
     $this->tls=$tls;
-    $this->binddn=$this->convert($binddn);
+    $this->binddn=LDAP::convert($binddn);
 
     $this->bindpw=$bindpw;
     $this->hostname=$hostname;
@@ -62,7 +62,7 @@ class LDAP{
       (   => OB
       )   => CB
       /   => SL                                                                  */
-  function convert($dn)
+  static function convert($dn)
   {
     if (SPECIALS_OVERRIDE == TRUE){
       $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
@@ -79,7 +79,7 @@ class LDAP{
      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)
+  static function fix($dn)
   {
     if (SPECIALS_OVERRIDE == TRUE){
       return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
@@ -106,7 +106,7 @@ class LDAP{
       }
 
       $this->error = "No Error";
-      if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
+      if ($bid = @ldap_bind($this->cid, LDAP::fix($this->binddn), $this->bindpw)) {
         $this->error = "Success";
         $this->hascon=true;
       } else {
@@ -126,7 +126,7 @@ class LDAP{
   function rebind($ldap, $referral)
   {
     $credentials= $this->get_credentials($referral);
-    if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
+    if (@ldap_bind($ldap, LDAP::fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
       $this->error = "Success";
       $this->hascon=true;
       $this->reconnect= true;
@@ -164,7 +164,7 @@ class LDAP{
     if ($dir == "..")
       $this->basedn = $this->getParentDir();
     else
-      $this->basedn = $this->convert($dir);
+      $this->basedn = LDAP::convert($dir);
   }
 
   function getParentDir($basedn = "")
@@ -172,7 +172,7 @@ class LDAP{
     if ($basedn=="")
       $basedn = $this->basedn;
     else
-      $basedn = $this->convert($this->basedn);
+      $basedn = LDAP::convert($this->basedn);
     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
   }
 
@@ -184,7 +184,7 @@ class LDAP{
       $start = microtime();
    
       $this->clearResult();
-      $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
+      $this->sr = @ldap_search($this->cid, LDAP::fix($this->basedn), $filter, $attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -197,7 +197,7 @@ class LDAP{
         }
       }
 
-      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".LDAP::fix($this->basedn)."', '$filter')");
       return($this->sr);
     }else{
       $this->error = "Could not connect to LDAP server";
@@ -213,11 +213,10 @@ class LDAP{
       if ($basedn == "")
         $basedn = $this->basedn;
       else
-        $basedn= $this->convert($basedn);
+        $basedn= LDAP::convert($basedn);
   
       $start = microtime();
-
-      $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
+      $this->sr = @ldap_list($this->cid, LDAP::fix($basedn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -230,7 +229,7 @@ class LDAP{
         }
       }
 
-      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
+      $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".LDAP::fix($basedn)."', '$filter')");
 
       return($this->sr);
     }else{
@@ -245,7 +244,7 @@ class LDAP{
       if ($this->reconnect) $this->connect();
       $this->clearResult();
       $filter = "(objectclass=*)";
-      $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
+      $this->sr = @ldap_read($this->cid, LDAP::fix($dn), $filter,$attrs);
       $this->error = @ldap_error($this->cid);
       $this->resetResult();
       $this->hasres=true;
@@ -276,15 +275,19 @@ class LDAP{
       if($this->hasres){
         if ($this->start == 0)
         {
-          $this->start = 1;
-          $this->re= @ldap_first_entry($this->cid, $this->sr);
+          if ($this->sr){
+            $this->start = 1;
+            $this->re= @ldap_first_entry($this->cid, $this->sr);
+          } else {
+            return array();
+          }
         } else {
           $this->re= @ldap_next_entry($this->cid, $this->re);
         }
         if ($this->re)
         {
           $att= @ldap_get_attributes($this->cid, $this->re);
-          $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
+          $att['dn']= trim(LDAP::convert(@ldap_get_dn($this->cid, $this->re)));
         }
         $this->error = @ldap_error($this->cid);
         if (!isset($att)){
@@ -328,7 +331,7 @@ class LDAP{
           $rv = @ldap_get_dn($this->cid, $this->re);
         
           $this->error = @ldap_error($this->cid);
-          return(trim($this->convert($rv)));
+          return(trim(LDAP::convert($rv)));
            }
       }else{
         $this->error = "Perform a Fetch with no Search";
@@ -364,7 +367,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
+      $r = @ldap_mod_del($this->cid, LDAP::fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -380,7 +383,7 @@ class LDAP{
       if ($dn == "")
         $dn = $this->basedn;
 
-      $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
+      $r = @ldap_mod_replace($this->cid, LDAP::fix($dn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r);
     }else{
@@ -393,7 +396,7 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_delete($this->cid, $this->fix($deletedn));
+      $r = @ldap_delete($this->cid, LDAP::fix($deletedn));
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -432,7 +435,7 @@ class LDAP{
       }
       
       /* Finally Delete own Node */
-      $r = @ldap_delete($this->cid, $this->fix($deletedn));
+      $r = @ldap_delete($this->cid, LDAP::fix($deletedn));
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -445,19 +448,19 @@ class LDAP{
   */
   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
   {
-    error_reporting(E_ALL);
+    error_reporting(E_ALL | E_STRICT);
     
     if($is_first){
-      echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
+      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>";
+        echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
       }else{
         $tmp = split(",",$sourcedn);
         
         echo "&nbsp;<b>"._("Object").":</b> ";
 
-        $deststr = @LDAP::fix($destinationdn);
+        $deststr = LDAP::fix($destinationdn);
         if(strlen($deststr) > 96){
           $deststr = substr($deststr,0,96)."...";
         }
@@ -497,7 +500,7 @@ class LDAP{
   
         /* check if this is a department */
         if(in_array("organizationalUnit",$attr['objectClass'])){
-          $attr['dn'] = $this->convert($destinationdn);
+          $attr['dn'] = LDAP::convert($destinationdn);
           $this->cd($basedn);
           $this->create_missing_trees($destinationdn);
           $this->cd($destinationdn);
@@ -531,7 +534,7 @@ class LDAP{
           /* If this is no department */
           foreach($attr as $key => $value){
             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
-              $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
+              $sr= ldap_read($this->cid, LDAP::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;
@@ -549,6 +552,7 @@ class LDAP{
           unset($attr['dn']);
 
           if((!in_array("gosaApplication" , $attr['objectClass'])) && (!in_array("gotoMimeType", $attr['objectClass']))){
+            $attr['FAIdebianRelease'] = $destinationName;
             if($type=="branch"){
               $attr['FAIstate'] ="branch";
             }elseif($type=="freeze"){
@@ -572,7 +576,7 @@ class LDAP{
           }
 
           if($this->error != "Success"){
-            /* Some error occured */
+            /* Some error occurred */
             print "---------------------------------------------";
             print $this->get_error()."<br>";
             print $sourcedn."<br>";
@@ -583,6 +587,8 @@ class LDAP{
         }
       }
 
+      echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
+
       $this->ls ("(objectClass=*)",$sourcedn);
       while ($this->fetch()){
         $deldn= $this->getDN();
@@ -615,7 +621,7 @@ class LDAP{
     }
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
+      $r = @ldap_modify($this->cid, LDAP::fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -628,7 +634,7 @@ class LDAP{
   {
     if($this->hascon){
       if ($this->reconnect) $this->connect();
-      $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
+      $r = @ldap_add($this->cid, LDAP::fix($this->basedn), $attrs);
       $this->error = @ldap_error($this->cid);
       return($r ? $r : 0);
     }else{
@@ -639,19 +645,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(gosa_ldap_explode_dn($real_path));
+
+    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;
@@ -682,36 +695,98 @@ 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();
@@ -735,7 +810,7 @@ class LDAP{
   {
     $data= "";
     if ($this->reconnect) $this->connect();
-    $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
+    $sr= @ldap_read($this->cid, LDAP::fix($dn), "objectClass=*", array("$name"));
 
     /* fill data from LDAP */
     if ($sr) {
@@ -744,7 +819,6 @@ class LDAP{
         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
           $data= $info[0];
         }
-
       }
     }
     if($r_array==0)
@@ -785,14 +859,14 @@ class LDAP{
     $url= preg_replace('!\?\?.*$!', '', $url);
     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
 
-    if ($referrals == NULL){
+    if ($referrals === NULL){
       $referrals= $this->referrals;
     }
 
     if (isset($referrals[$server])){
       return ($referrals[$server]);
     } else {
-      $ret['ADMIN']= $this->fix($this->binddn);
+      $ret['ADMIN']= LDAP::fix($this->binddn);
       $ret['PASSWORD']= $this->bindpw;
     }
 
@@ -856,7 +930,7 @@ class LDAP{
     }
 
     /* Searching Ldap Tree */
-    $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
+    $sr= @ldap_read($this->cid, LDAP::fix($dn), $filter, $name);
 
     /* Get the first entry */   
     $entry= @ldap_first_entry($this->cid, $sr);
@@ -900,7 +974,7 @@ class LDAP{
 
   function dn_exists($dn)
   {
-    return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
+    return @ldap_list($this->cid, LDAP::fix($dn), "(objectClass=*)", array("objectClass"));
   }
   
 
@@ -988,7 +1062,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];
@@ -1040,6 +1114,13 @@ class LDAP{
   */
   function import_single_entry($str_attr,$modify,$delete)
   {
+    global $config;
+
+    if(!$config){
+      trigger_error("Can't import ldif, can't read config object.");
+    }
+  
+
     if($this->reconnect) $this->connect();
 
     $ret = false;
@@ -1117,7 +1198,8 @@ class LDAP{
      
       /* Create missing trees */
       $this->cd ($this->basedn);
-      $this->create_missing_trees($data['dn']);
+      $this->cd($config->current['BASE']);
+      $this->create_missing_trees(preg_replace("/^[^,]+,/","",$data['dn']));
       $this->cd($data['dn']);
 
       $dn = $data['dn'];
@@ -1181,16 +1263,28 @@ class LDAP{
   
   function get_objectclasses()
   {
-         $objectclasses = array();
-       
+    $objectclasses = array();
+    global $config;
+
+    /* Only read schema if it is allowed */
+    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
+         /* Get list of objectclasses and fill array */
          $nb= $attr[0]['subschemasubentry'][0];
          $objectclasses= array();
          $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
@@ -1199,15 +1293,74 @@ 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'])){
@@ -1230,6 +1383,56 @@ class LDAP{
       }
     }
   }
+
+
+  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: