Code

d50b78d55f058dfa0a7d747833f1865986aed398
[gosa.git] / include / class_ldap.inc
1 <?php
2 /*****************************************************************************
3   newldap.inc - version 1.0
4   Copyright (C) 2003 Alejandro Escanero Blanco <aescanero@chaosdimension.org>
5   Copyright (C) 2004-2006 Cajus Pollmeier <pollmeier@gonicus.de>
7   Based in code of ldap.inc of
8   Copyright (C) 1998  Eric Kilfoil <eric@ipass.net>
9  *****************************************************************************/
11 define("ALREADY_EXISTING_ENTRY",-10001);
12 define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
13 define("NO_FILE_UPLOADED",10003);
14 define("INSERT_OK",10000);
15 define("SPECIALS_OVERRIDE", TRUE);
17 class LDAP{
19   var $hascon   =false;
20   var $hasres   =false;
21   var $reconnect=false;
22   var $tls      = false;
23   var $basedn   ="";
24   var $cid;
25   var $error    = ""; // Any error messages to be returned can be put here
26   var $start    = 0; // 0 if we are fetching the first entry, otherwise 1
27   var $objectClasses = array(); // Information read from slapd.oc.conf
28   var $binddn   = "";
29   var $bindpw   = "";
30   var $hostname = "";
31   var $follow_referral = FALSE;
32   var $referrals= array();
33   var $max_ldap_query_time = 0;   // 0, empty or negative values will disable this check 
35   function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
36   {
37     global $config;
38     $this->follow_referral= $follow_referral;
39     $this->tls=$tls;
40     $this->binddn=$this->convert($binddn);
42     $this->bindpw=$bindpw;
43     $this->hostname=$hostname;
45     /* Check if MAX_LDAP_QUERY_TIME is defined */ 
46     if(isset($config->data['MAIN']['MAX_LDAP_QUERY_TIME'])){
47       $str = $config->data['MAIN']['MAX_LDAP_QUERY_TIME'];
48       $this->max_ldap_query_time = (float)($str);
49     }
51     $this->connect();
52   }
55   /* Function to replace all problematic characters inside a DN by \001XX, where
56      \001 is decoded to chr(1) [ctrl+a]. It is not impossible, but very unlikely
57      that this character is inside a DN.
58      
59      Currently used codes:
60       ,   => CO
61       \2C => CO
62       (   => OB
63       )   => CB
64       /   => SL                                                                  */
65   function convert($dn)
66   {
67     if (SPECIALS_OVERRIDE == TRUE){
68       $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//"),
69                            array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL"),
70                            $dn);
71       return (preg_replace('/,\s+/', ',', $tmp));
72     } else {
73       return ($dn);
74     }
75   }
78   /* Function to fix all problematic characters inside a DN by replacing \001XX
79      codes to their original values. See "convert" for mor information. 
80      ',' characters are always expanded to \, (not \2C), since all tested LDAP
81      servers seem to take it the correct way.                                  */
82   function fix($dn)
83   {
84     if (SPECIALS_OVERRIDE == TRUE){
85       return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/"),
86                            array("\,", "(", ")", "/"),
87                            $dn));
88     } else {
89       return ($dn);
90     }
91   }
94   function connect()
95   {
96     $this->hascon=false;
97     $this->reconnect=false;
98     if ($this->cid= @ldap_connect($this->hostname)) {
99       @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
100       if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
101         @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
102         @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
103       }
104       if (function_exists("ldap_start_tls") && $this->tls){
105         @ldap_start_tls($this->cid);
106       }
108       $this->error = "No Error";
109       if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
110         $this->error = "Success";
111         $this->hascon=true;
112       } else {
113         if ($this->reconnect){
114           if ($this->error != "Success"){
115             $this->error = "Could not rebind to " . $this->binddn;
116           }
117         } else {
118           $this->error = "Could not bind to " . $this->binddn;
119         }
120       }
121     } else {
122       $this->error = "Could not connect to LDAP server";
123     }
124   }
126   function rebind($ldap, $referral)
127   {
128     $credentials= $this->get_credentials($referral);
129     if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
130       $this->error = "Success";
131       $this->hascon=true;
132       $this->reconnect= true;
133       return (0);
134     } else {
135       $this->error = "Could not bind to " . $credentials['ADMIN'];
136       return NULL;
137     }
138   }
140   function reconnect()
141   {
142     if ($this->reconnect){
143       @ldap_unbind($this->cid);
144       $this->cid = NULL;
145     }
146   }
148   function unbind()
149   {
150     @ldap_unbind($this->cid);
151     $this->cid = NULL;
152   }
154   function disconnect()
155   {
156     if($this->hascon){
157       @ldap_close($this->cid);
158       $this->hascon=false;
159     }
160   }
162   function cd($dir)
163   {
164     if ($dir == "..")
165       $this->basedn = $this->getParentDir();
166     else
167       $this->basedn = $this->convert($dir);
168   }
170   function getParentDir($basedn = "")
171   {
172     if ($basedn=="")
173       $basedn = $this->basedn;
174     else
175       $basedn = $this->convert($this->basedn);
176     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
177   }
179   function search($filter, $attrs= array())
180   {
181     if($this->hascon){
182       if ($this->reconnect) $this->connect();
184       $start = microtime();
185    
186       $this->clearResult();
187       $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
188       $this->error = @ldap_error($this->cid);
189       $this->resetResult();
190       $this->hasres=true;
191    
192       /* Check if query took longer as specified in max_ldap_query_time */
193       if($this->max_ldap_query_time){
194         $diff = get_MicroTimeDiff($start,microtime());
195         if($diff > $this->max_ldap_query_time){
196           print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
197         }
198       }
200       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
201       return($this->sr);
202     }else{
203       $this->error = "Could not connect to LDAP server";
204       return("");
205     }
206   }
208   function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
209   {
210     if($this->hascon){
211       if ($this->reconnect) $this->connect();
212       $this->clearResult();
213       if ($basedn == "")
214         $basedn = $this->basedn;
215       else
216         $basedn= $this->convert($basedn);
217   
218       $start = microtime();
220       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
221       $this->error = @ldap_error($this->cid);
222       $this->resetResult();
223       $this->hasres=true;
225        /* Check if query took longer as specified in max_ldap_query_time */
226       if($this->max_ldap_query_time){
227         $diff = get_MicroTimeDiff($start,microtime());
228         if($diff > $this->max_ldap_query_time){
229           print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
230         }
231       }
233       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
235       return($this->sr);
236     }else{
237       $this->error = "Could not connect to LDAP server";
238       return("");
239     }
240   }
242   function cat($dn,$attrs= array("*"))
243   {
244     if($this->hascon){
245       if ($this->reconnect) $this->connect();
246       $this->clearResult();
247       $filter = "(objectclass=*)";
248       $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
249       $this->error = @ldap_error($this->cid);
250       $this->resetResult();
251       $this->hasres=true;
252       return($this->sr);
253     }else{
254       $this->error = "Could not connect to LDAP server";
255       return("");
256     }
257   }
259   function set_size_limit($size)
260   {
261     /* Ignore zero settings */
262     if ($size == 0){
263       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
264     }
265     if($this->hascon){
266       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
267     } else {
268       $this->error = "Could not connect to LDAP server";
269     }
270   }
272   function fetch()
273   {
274     $att= array();
275     if($this->hascon){
276       if($this->hasres){
277         if ($this->start == 0)
278         {
279           $this->start = 1;
280           $this->re= @ldap_first_entry($this->cid, $this->sr);
281         } else {
282           $this->re= @ldap_next_entry($this->cid, $this->re);
283         }
284         if ($this->re)
285         {
286           $att= @ldap_get_attributes($this->cid, $this->re);
287           $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
288         }
289         $this->error = @ldap_error($this->cid);
290         if (!isset($att)){
291           $att= array();
292         }
293         return($att);
294       }else{
295         $this->error = "Perform a Fetch with no Search";
296         return("");
297       }
298     }else{
299       $this->error = "Could not connect to LDAP server";
300       return("");
301     }
302   }
304   function resetResult()
305   {
306     $this->start = 0;
307   }
309   function clearResult()
310   {
311     if($this->hasres){
312       $this->hasres = false;
313       @ldap_free_result($this->sr);
314     }
315   }
317   function getDN()
318   {
319     if($this->hascon){
320       if($this->hasres){
322         if(!$this->re)
323           {
324           $this->error = "Perform a Fetch with no valid Result";
325           }
326           else
327           {
328           $rv = @ldap_get_dn($this->cid, $this->re);
329         
330           $this->error = @ldap_error($this->cid);
331           return(trim($this->convert($rv)));
332            }
333       }else{
334         $this->error = "Perform a Fetch with no Search";
335         return("");
336       }
337     }else{
338       $this->error = "Could not connect to LDAP server";
339       return("");
340     }
341   }
343   function count()
344   {
345     if($this->hascon){
346       if($this->hasres){
347         $rv = @ldap_count_entries($this->cid, $this->sr);
348         $this->error = @ldap_error($this->cid);
349         return($rv);
350       }else{
351         $this->error = "Perform a Fetch with no Search";
352         return("");
353       }
354     }else{
355       $this->error = "Could not connect to LDAP server";
356       return("");
357     }
358   }
360   function rm($attrs = "", $dn = "")
361   {
362     if($this->hascon){
363       if ($this->reconnect) $this->connect();
364       if ($dn == "")
365         $dn = $this->basedn;
367       $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
368       $this->error = @ldap_error($this->cid);
369       return($r);
370     }else{
371       $this->error = "Could not connect to LDAP server";
372       return("");
373     }
374   }
376   function rename($attrs, $dn = "")
377   {
378     if($this->hascon){
379       if ($this->reconnect) $this->connect();
380       if ($dn == "")
381         $dn = $this->basedn;
383       $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
384       $this->error = @ldap_error($this->cid);
385       return($r);
386     }else{
387       $this->error = "Could not connect to LDAP server";
388       return("");
389     }
390   }
392   function rmdir($deletedn)
393   {
394     if($this->hascon){
395       if ($this->reconnect) $this->connect();
396       $r = @ldap_delete($this->cid, $this->fix($deletedn));
397       $this->error = @ldap_error($this->cid);
398       return($r ? $r : 0);
399     }else{
400       $this->error = "Could not connect to LDAP server";
401       return("");
402     }
403   }
405   /**
406   *  Function rmdir_recursive
407   *
408   *  Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
409   *  Parameters:  The dn to delete
410   *  GiveBack:    True on sucessfull , 0 in error, and "" when we don't get a ldap conection
411   *
412   */
414   function rmdir_recursive($deletedn)
415   {
416     if($this->hascon){
417       if ($this->reconnect) $this->connect();
418       $delarray= array();
419         
420       /* Get sorted list of dn's to delete */
421       $this->ls ("(objectClass=*)",$deletedn);
422       while ($this->fetch()){
423         $deldn= $this->getDN();
424         $delarray[$deldn]= strlen($deldn);
425       }
426       arsort ($delarray);
427       reset ($delarray);
429       /* Really Delete ALL dn's in subtree */
430       foreach ($delarray as $key => $value){
431         $this->rmdir_recursive($key);
432       }
433       
434       /* Finally Delete own Node */
435       $r = @ldap_delete($this->cid, $this->fix($deletedn));
436       $this->error = @ldap_error($this->cid);
437       return($r ? $r : 0);
438     }else{
439       $this->error = "Could not connect to LDAP server";
440       return("");
441     }
442   }
444   /* Copy given attributes and sub-dns with attributes to destination dn 
445   */
446   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
447   {
448     error_reporting(E_ALL);
449     
450     if($is_first){
451       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
452     }else{
453       if(preg_match("/^ou=/",$sourcedn)){
454         echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
455       }else{
456         $tmp = split(",",$sourcedn);
457         
458         echo "&nbsp;<b>"._("Object").":</b> ";
460         $deststr = @LDAP::fix($destinationdn);
461         if(strlen($deststr) > 96){
462           $deststr = substr($deststr,0,96)."...";
463         }
465         echo $deststr."<br>";
466       }
467     }
469     flush();
470     
471     if($this->hascon){
472       if ($this->reconnect) $this->connect();
474       /* Save base dn */
475       $basedn= $this->basedn;
476       $delarray= array();
477      
478       /* Check if destination entry already exists */
479       $this->cat($destinationdn);
481       if($this->count()){
482         return;
483       }else{
484         
485         $this->clearResult();
487         /* Get source entry */
488         $this->cd($basedn);
489         $this->cat($sourcedn);
490         $attr = $this->fetch();
492         /* Error while fetching object / attribute abort*/
493         if((!$attr) || (count($attr)) ==0) {
494           echo _("Error while fetching source dn - aborted!");
495           return;
496         }
497   
498         /* check if this is a department */
499         if(in_array("organizationalUnit",$attr['objectClass'])){
500           $attr['dn'] = $this->convert($destinationdn);
501           $this->cd($basedn);
502           $this->create_missing_trees($destinationdn);
503           $this->cd($destinationdn);
505           /* If is first entry, append FAIbranch to department entry */
506           if($is_first){
507             $this->cat($destinationdn);
508             $attr= $this->fetch();
510             /* Filter unneeded informations */
511             foreach($attr as $key => $value){
512               if(is_numeric($key)) unset($attr[$key]);
513               if(isset($attr[$key]['count'])){
514                 if(is_array($attr[$key])){
515                   unset($attr[$key]['count']);
516                 }
517               }
518             }
519             
520             unset($attr['count']);
521             unset($attr['dn']);
523             /* Add marking attribute */
524             $attr['objectClass'][] = "FAIbranch";
525             
526             /* Add this entry */
527             $this->modify($attr);
528           }
529         }else{
531           /* If this is no department */
532           foreach($attr as $key => $value){
533             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
534               $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
535               $ei= ldap_first_entry($this->cid, $sr);
536               if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
537                 $attr[$key] = $tmp;
538               }
539             }
541             if(is_numeric($key)) unset($attr[$key]);
542             if(isset($attr[$key]['count'])){
543               if(is_array($attr[$key])){
544                 unset($attr[$key]['count']);
545               }
546             }
547           }
548           unset($attr['count']);
549           unset($attr['dn']);
551           if((!in_array("gosaApplication" , $attr['objectClass'])) && (!in_array("gotoMimeType", $attr['objectClass']))){
552             if($type=="branch"){
553               $attr['FAIstate'] ="branch";
554             }elseif($type=="freeze"){
555               $attr['FAIstate'] ="freeze";
556             }else{
557               print_red(_("Unknown FAIstate %s"),$type);
558             }
559           }
561           /* Replace FAIdebianRelease with new release name */
562           if(in_array("FAIpackageList" , $attr['objectClass'])){
563             $attr['FAIdebianRelease'] = $destinationName; 
564           }
566           /* Add entry */
567           $this->cd($destinationdn);
568           $this->cat($destinationdn);
569           $a = $this->fetch();
570           if(!count($a)){
571             $this->add($attr);
572           }
574           if($this->error != "Success"){
575             /* Some error occured */
576             print "---------------------------------------------";
577             print $this->get_error()."<br>";
578             print $sourcedn."<br>";
579             print $destinationdn."<br>";
580             print_a( $attr);
581             exit();
582           }          
583         }
584       }
586       echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
588       $this->ls ("(objectClass=*)",$sourcedn);
589       while ($this->fetch()){
590         $deldn= $this->getDN();
591         $delarray[$deldn]= strlen($deldn);
592       }
593       asort ($delarray);
594       reset ($delarray);
596        $depth ++;
597       foreach($delarray as $dn => $bla){
598         if($dn != $destinationdn){
599           $this->cd($basedn);
600           $item = $this->fetch($this->cat($dn));
601           if(!in_array("FAIbranch",$item['objectClass'])){
602             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
603           } 
604         }
605       }
606     }
607     if($is_first){
608       echo "<p class='seperator'>&nbsp;</p>";
609     }
611   }
613   function modify($attrs)
614   {
615     if(count($attrs) == 0){
616       return (0);
617     }
618     if($this->hascon){
619       if ($this->reconnect) $this->connect();
620       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
621       $this->error = @ldap_error($this->cid);
622       return($r ? $r : 0);
623     }else{
624       $this->error = "Could not connect to LDAP server";
625       return("");
626     }
627   }
629   function add($attrs)
630   {
631     if($this->hascon){
632       if ($this->reconnect) $this->connect();
633       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
634       $this->error = @ldap_error($this->cid);
635       return($r ? $r : 0);
636     }else{
637       $this->error = "Could not connect to LDAP server";
638       return("");
639     }
640   }
642   function create_missing_trees($target)
643   {
644     /* Ignore create_missing trees if the base equals target */
645     if ($target == $this->basedn){
646      return;
647     }
649     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
650     $l= array_reverse(gosa_ldap_explode_dn($real_path));
651     unset($l['count']);
652     $cdn= $this->basedn;
653     $tag= "";
655     foreach ($l as $part){
656       $cdn= "$part,$cdn";
658       /* Ignore referrals */
659       $found= false;
660       foreach($this->referrals as $ref){
661         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
662         if ($base == $cdn){
663           $found= true;
664           break;
665         }
666       }
667       if ($found){
668         continue;
669       }
671       $this->cat ($cdn);
672       $attrs= $this->fetch();
674       /* Create missing entry? */
675       if (count ($attrs)){
676       
677         /* Catch the tag - if present */
678         if (isset($attrs['gosaUnitTag'][0])){
679           $tag= $attrs['gosaUnitTag'][0];
680         }
682       } else {
683         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
684         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
686         $na= array();
687         switch ($type){
688           case 'ou':
689             if ($tag != ""){
690               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
691               $na["gosaUnitTag"]= $tag;
692             } else {
693               $na["objectClass"]= "organizationalUnit";
694             }
695             $na["ou"]= $param;
696             break;
697           case 'dc':
698             if ($tag != ""){
699               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
700               $na["gosaUnitTag"]= $tag;
701             } else {
702               $na["objectClass"]= array("dcObject", "top", "locality");
703             }
704             $na["dc"]= $param;
705             break;
706           default:
707             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
708             echo $_SESSION['errors'];
709             exit;
710         }
711         $this->cd($cdn);
712         $this->add($na);
713       }
714     }
715   }
717   function recursive_remove()
718   {
719     $delarray= array();
721     /* Get sorted list of dn's to delete */
722     $this->search ("(objectClass=*)");
723     while ($this->fetch()){
724       $deldn= $this->getDN();
725       $delarray[$deldn]= strlen($deldn);
726     }
727     arsort ($delarray);
728     reset ($delarray);
730     /* Delete all dn's in subtree */
731     foreach ($delarray as $key => $value){
732       $this->rmdir($key);
733     }
734   }
736   function get_attribute($dn, $name,$r_array=0)
737   {
738     $data= "";
739     if ($this->reconnect) $this->connect();
740     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
742     /* fill data from LDAP */
743     if ($sr) {
744       $ei= @ldap_first_entry($this->cid, $sr);
745       if ($ei) {
746         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
747           $data= $info[0];
748         }
750       }
751     }
752     if($r_array==0)
753     return ($data);
754     else
755     return ($info);
756   
757   
758   }
759  
762   function get_additional_error()
763   {
764     $error= "";
765     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
766     return ($error);
767   }
769   function get_error()
770   {
771     if ($this->error == 'Success'){
772       return $this->error;
773     } else {
774       $adderror= $this->get_additional_error();
775       if ($adderror != ""){
776         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
777       } else {
778         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
779       }
780       return $error;
781     }
782   }
784   function get_credentials($url, $referrals= NULL)
785   {
786     $ret= array();
787     $url= preg_replace('!\?\?.*$!', '', $url);
788     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
790     if ($referrals == NULL){
791       $referrals= $this->referrals;
792     }
794     if (isset($referrals[$server])){
795       return ($referrals[$server]);
796     } else {
797       $ret['ADMIN']= $this->fix($this->binddn);
798       $ret['PASSWORD']= $this->bindpw;
799     }
801     return ($ret);
802   }
805   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
806   {
807     $display= "";
809     if ($recursive){
810       $this->cd($dn);
811       $this->ls($filter,$dn, array('dn','objectClass'));
812       $deps = array();
814       $display .= $this->gen_one_entry($dn)."\n";
816       while ($attrs= $this->fetch()){
817         $deps[] = $attrs['dn'];
818       }
819       foreach($deps as $dn){
820         $display .= $this->gen_ldif($dn, $filter,$attributes,$recursive);
821       }
822     } else {
823       $display.= $this->gen_one_entry($dn);
824     }
825     return ($display);
826   }
829   function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
830   {
831     $display= array();
833       $this->cd($dn);
834       $this->search("$filter");
836       $i=0;
837       while ($attrs= $this->fetch()){
838         $j=0;
840         foreach ($attributes as $at){
841           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
842           $j++;
843         }
845         $i++;
846       }
848     return ($display);
849   }
852   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
853   {
854     $ret = "";
855     $data = "";
856     if($this->reconnect){
857       $this->connect();
858     }
860     /* Searching Ldap Tree */
861     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
863     /* Get the first entry */   
864     $entry= @ldap_first_entry($this->cid, $sr);
866     /* Get all attributes related to that Objekt */
867     $atts = array();
868     
869     /* Assemble dn */
870     $atts[0]['name']  = "dn";
871     $atts[0]['value'] = array('count' => 1, 0 => $dn);
873     /* Reset index */
874     $i = 1 ; 
875   $identifier = array();
876     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
877     while ($attribute) {
878       $i++;
879       $atts[$i]['name']  = $attribute;
880       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
882       /* Next one */
883       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
884     }
886     foreach($atts as $at)
887     {
888       for ($i= 0; $i<$at['value']['count']; $i++){
890         /* Check if we must encode the data */
891         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
892           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
893         } else {
894           $ret .= $at['name'].": ".$at['value'][$i]."\n";
895         }
896       }
897     }
899     return($ret);
900   }
903   function dn_exists($dn)
904   {
905     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
906   }
907   
910   /*  This funktion imports ldifs 
911         
912       If DeleteOldEntries is true, the destination entry will be deleted first. 
913       If JustModify is true the destination entry will only be touched by the attributes specified in the ldif.
914       if JustMofify id false the destination dn will be overwritten by the new ldif. 
915     */
917   function import_complete_ldif($str_attr,&$error,$JustModify,$DeleteOldEntries)
918   {
919     if($this->reconnect) $this->connect();
921     /* First we have to splitt the string ito detect empty lines
922        An empty line indicates an new Entry */
923     $entries = split("\n",$str_attr);
925     $data = "";
926     $cnt = 0; 
927     $current_line = 0;
929     /* FIX ldif */
930     $last = "";
931     $tmp  = "";
932     $i = 0;
933     foreach($entries as $entry){
934       if(preg_match("/^ /",$entry)){
935         $tmp[$i] .= trim($entry);
936       }else{
937         $i ++;
938         $tmp[$i] = trim($entry);
939       }
940     }
942     /* Every single line ... */
943     foreach($tmp as $entry) {
944       $current_line ++;
946       /* Removing Spaces to .. 
947          .. test if a new entry begins */
948       $tmp  = str_replace(" ","",$data );
950       /* .. prevent empty lines in an entry */
951       $tmp2 = str_replace(" ","",$entry);
953       /* If the Block ends (Empty Line) */
954       if((empty($entry))&&(!empty($tmp))) {
955         /* Add collected lines as a complete block */
956         $all[$cnt] = $data;
957         $cnt ++;
958         $data ="";
959       } else {
961         /* Append lines ... */
962         if(!empty($tmp2)) {
963           /* check if we need base64_decode for this line */
964           if(ereg("::",$tmp2))
965           {
966             $encoded = split("::",$entry);
967             $attr  = trim($encoded[0]);
968             $value = base64_decode(trim($encoded[1]));
969             /* Add linenumber */
970             $data .= $current_line."#".base64_encode($attr.":".$value)."\n";
971           }
972           else
973           {
974             /* Add Linenumber */ 
975             $data .= $current_line."#".base64_encode($entry)."\n";
976           }
977         }
978       }
979     }
981     /* The Data we collected is not in the array all[];
982        For example the Data is stored like this..
984        all[0] = "1#dn : .... \n 
985        2#ObjectType: person \n ...."
986        
987        Now we check every insertblock and try to insert */
988     foreach ( $all as $single) {
989       $lineone = split("\n",$single);  
990       $ndn = split("#", $lineone[0]);
991       $line = base64_decode($ndn[1]);
993       $dnn = split (":",$line);
994       $current_line = $ndn[0];
995       $dn    = $dnn[0];
996       $value = $dnn[1];
998       /* Every block must begin with a dn */
999       if($dn != "dn") {
1000         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1001         return -2;  
1002       }
1004       /* Should we use Modify instead of Add */
1005       $usemodify= false;
1007       /* Delete before insert */
1008       $usermdir= false;
1009     
1010       /* The dn address already exists, Don't delete destination entry, overwrite it */
1011       if (($this->dn_exists($value))&&((!$JustModify)&&(!$DeleteOldEntries))) {
1013         $usermdir = $usemodify = false;
1015       /* Delete old entry first, then add new */
1016       } elseif(($this->dn_exists($value))&&($DeleteOldEntries)){
1018         /* Delete first, then add */
1019         $usermdir = true;        
1021       } elseif(($this->dn_exists($value))&&($JustModify)) {
1022         
1023         /* Modify instead of Add */
1024         $usemodify = true;
1025       }
1026      
1027       /* If we can't Import, return with a file error */
1028       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1029         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1030                         $current_line);
1031         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
1032     }
1034     return (INSERT_OK);
1035   }
1038   /* Imports a single entry 
1039       If $delete is true;  The old entry will be deleted if it exists.
1040       if $modify is true;  All variables that are not touched by the new ldif will be kept.
1041       if $modify is false; The new ldif overwrites the old entry, and all untouched attributes get lost.
1042   */
1043   function import_single_entry($str_attr,$modify,$delete)
1044   {
1045     if($this->reconnect) $this->connect();
1047     $ret = false;
1048     $rows= split("\n",$str_attr);
1049     $data= false;
1051     foreach($rows as $row) {
1052       
1053       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1054          Linenumbers) Linenumbers are use like this 123#attribute : value */
1055       if(!empty($row)) {
1056         if(strpos($row,"#")!=FALSE) {
1058           /* We are using line numbers 
1059              Because there is a # before a : */
1060           $tmp1= split("#",$row);
1061           $current_line= $tmp1[0];
1062           $row= base64_decode($tmp1[1]);
1063         }
1065         /* Split the line into  attribute  and value */
1066         $attr   = split(":", $row,2);
1067         $attr[0]= trim($attr[0]);  /* attribute */
1068         $attr[1]= $attr[1];  /* value */
1070         /* Check :: was used to indicate base64_encoded strings */
1071         if($attr[1][0] == ":"){
1072           $attr[1]=trim(preg_replace("/^:/","",$attr[1]));
1073           $attr[1]=base64_decode($attr[1]);
1074         }
1076         $attr[1] = trim($attr[1]);
1078         /* Check for attributes that are used more than once */
1079         if(!isset($data[$attr[0]])) {
1080           $data[$attr[0]]=$attr[1];
1081         } else {
1082           $tmp = $data[$attr[0]];
1084           if(!is_array($tmp)) {
1085             $new[0]=$tmp;
1086             $new[1]=$attr[1];
1087             $datas[$attr[0]]['count']=1;             
1088             $data[$attr[0]]=$new;
1089           } else {
1090             $cnt = $datas[$attr[0]]['count'];           
1091             $cnt ++;
1092             $data[$attr[0]][$cnt]=$attr[1];
1093             $datas[$attr[0]]['count'] = $cnt;
1094           }
1095         }
1096       }
1097     }
1099     /* If dn is an index of data, we should try to insert the data */
1100     if(isset($data['dn'])) {
1102       /* Fix dn */
1103       $tmp = gosa_ldap_explode_dn($data['dn']);
1104       unset($tmp['count']);
1105       $newdn ="";
1106       foreach($tmp as $tm){
1107         $newdn.= trim($tm).",";
1108       }
1109       $newdn = preg_replace("/,$/","",$newdn);
1110       $data['dn'] = $newdn;
1111    
1112       /* Creating Entry */
1113       $this->cd($data['dn']);
1115       /* Delete existing entry */
1116       if($delete){
1117         $this->rmdir_recursive($data['dn']);
1118       }
1119      
1120       /* Create missing trees */
1121       $this->cd ($this->basedn);
1122       $this->create_missing_trees($data['dn']);
1123       $this->cd($data['dn']);
1125       $dn = $data['dn'];
1126       unset($data['dn']);
1127       
1128       if(!$modify){
1130         $this->cat($dn);
1131         if($this->count()){
1132         
1133           /* The destination entry exists, overwrite it with the new entry */
1134           $attrs = $this->fetch();
1135           foreach($attrs as $name => $value ){
1136             if(!is_numeric($name)){
1137               if(in_array($name,array("dn","count"))) continue;
1138               if(!isset($data[$name])){
1139                 $data[$name] = array();
1140               }
1141             }
1142           }
1143           $ret = $this->modify($data);
1144     
1145         }else{
1146     
1147           /* The destination entry doesn't exists, create it */
1148           $ret = $this->add($data);
1149         }
1151       } else {
1152         
1153         /* Keep all vars that aren't touched by this ldif */
1154         $ret = $this->modify($data);
1155       }
1156     }
1157     show_ldap_error($this->get_error(), sprintf(_("Ldap import with dn '%s' failed."),$dn));
1158     return($ret);
1159   }
1161   
1162   function importcsv($str)
1163   {
1164     $lines = split("\n",$str);
1165     foreach($lines as $line)
1166     {
1167       /* continue if theres a comment */
1168       if(substr(trim($line),0,1)=="#"){
1169         continue;
1170       }
1172       $line= str_replace ("\t\t","\t",$line);
1173       $line= str_replace ("\t"  ,"," ,$line);
1174       echo $line;
1176       $cells = split(",",$line )  ;
1177       $linet= str_replace ("\t\t",",",$line);
1178       $cells = split("\t",$line);
1179       $count = count($cells);  
1180     }
1182   }
1183   
1184   function get_objectclasses()
1185   {
1186           $objectclasses = array();
1187         
1188           # Get base to look for schema 
1189           $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1190           $attr = @ldap_get_entries($this->cid,$sr);
1191           if (!isset($attr[0]['subschemasubentry'][0])){
1192             return array();
1193           }
1194         
1195           # Get list of objectclasses
1196           $nb= $attr[0]['subschemasubentry'][0];
1197           $objectclasses= array();
1198           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1199           $attrs= ldap_get_entries($this->cid,$sr);
1200           if (!isset($attrs[0])){
1201             return array();
1202           }
1203           foreach ($attrs[0]['objectclasses'] as $val){
1204             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1205             if ($name != $val){
1206               $objectclasses[$name]= $val;
1207             }
1208           }
1209           
1210           return $objectclasses;
1211   }
1213   function log($string)
1214   {
1215     if (isset($_SESSION['config'])){
1216       $cfg= $_SESSION['config'];
1217       if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1218         syslog (LOG_INFO, $string);
1219       }
1220     }
1221   }
1223   /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1224   function getCn($dn){
1225     $simple= split(",", $dn);
1227     foreach($simple as $piece) {
1228       $partial= split("=", $piece);
1230       if($partial[0] == "cn"){
1231         return $partial[1];
1232       }
1233     }
1234   }
1237 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1238 ?>