Code

Fixed typo
[gosa.git] / include / class_ldap.inc
1 <?php
2 /*****************************************************************************
3   newldap.inc - version 1.0
4   Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
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')");
202       return($this->sr);
203     }else{
204       $this->error = "Could not connect to LDAP server";
205       return("");
206     }
207   }
209   function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
210   {
211     if($this->hascon){
212       if ($this->reconnect) $this->connect();
213       $this->clearResult();
214       if ($basedn == "")
215         $basedn = $this->basedn;
216       else
217         $basedn= $this->convert($basedn);
218   
219       $start = microtime();
221       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
222       $this->error = @ldap_error($this->cid);
223       $this->resetResult();
224       $this->hasres=true;
226        /* Check if query took longer as specified in max_ldap_query_time */
227       if($this->max_ldap_query_time){
228         $diff = get_MicroTimeDiff($start,microtime());
229         if($diff > $this->max_ldap_query_time){
230           print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
231         }
232       }
234       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
236       return($this->sr);
237     }else{
238       $this->error = "Could not connect to LDAP server";
239       return("");
240     }
241   }
243   function cat($dn,$attrs= array("*"))
244   {
245     if($this->hascon){
246       if ($this->reconnect) $this->connect();
247       $start = microtime();
248       $this->clearResult();
249       $filter = "(objectclass=*)";
250       $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
251       $this->error = @ldap_error($this->cid);
252       $this->resetResult();
253       $this->hasres=true;
254       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
255       return($this->sr);
256     }else{
257       $this->error = "Could not connect to LDAP server";
258       return("");
259     }
260   }
262   function set_size_limit($size)
263   {
264     /* Ignore zero settings */
265     if ($size == 0){
266       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
267     }
268     if($this->hascon){
269       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
270     } else {
271       $this->error = "Could not connect to LDAP server";
272     }
273   }
275   function fetch()
276   {
277     $att= array();
278     if($this->hascon){
279       if($this->hasres){
280         if ($this->start == 0)
281         {
282           $this->start = 1;
283           $this->re= @ldap_first_entry($this->cid, $this->sr);
284         } else {
285           $this->re= @ldap_next_entry($this->cid, $this->re);
286         }
287         if ($this->re)
288         {
289           $att= @ldap_get_attributes($this->cid, $this->re);
290           $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
291         }
292         $this->error = @ldap_error($this->cid);
293         if (!isset($att)){
294           $att= array();
295         }
296         return($att);
297       }else{
298         $this->error = "Perform a Fetch with no Search";
299         return("");
300       }
301     }else{
302       $this->error = "Could not connect to LDAP server";
303       return("");
304     }
305   }
307   function resetResult()
308   {
309     $this->start = 0;
310   }
312   function clearResult()
313   {
314     if($this->hasres){
315       $this->hasres = false;
316       @ldap_free_result($this->sr);
317     }
318   }
320   function getDN()
321   {
322     if($this->hascon){
323       if($this->hasres){
325         if(!$this->re)
326           {
327           $this->error = "Perform a Fetch with no valid Result";
328           }
329           else
330           {
331           $rv = @ldap_get_dn($this->cid, $this->re);
332         
333           $this->error = @ldap_error($this->cid);
334           return(trim($this->convert($rv)));
335            }
336       }else{
337         $this->error = "Perform a Fetch with no Search";
338         return("");
339       }
340     }else{
341       $this->error = "Could not connect to LDAP server";
342       return("");
343     }
344   }
346   function count()
347   {
348     if($this->hascon){
349       if($this->hasres){
350         $rv = @ldap_count_entries($this->cid, $this->sr);
351         $this->error = @ldap_error($this->cid);
352         return($rv);
353       }else{
354         $this->error = "Perform a Fetch with no Search";
355         return("");
356       }
357     }else{
358       $this->error = "Could not connect to LDAP server";
359       return("");
360     }
361   }
363   function rm($attrs = "", $dn = "")
364   {
365     if($this->hascon){
366       if ($this->reconnect) $this->connect();
367       if ($dn == "")
368         $dn = $this->basedn;
370       $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
371       $this->error = @ldap_error($this->cid);
372       return($r);
373     }else{
374       $this->error = "Could not connect to LDAP server";
375       return("");
376     }
377   }
379   function rename($attrs, $dn = "")
380   {
381     if($this->hascon){
382       if ($this->reconnect) $this->connect();
383       if ($dn == "")
384         $dn = $this->basedn;
386       $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
387       $this->error = @ldap_error($this->cid);
388       return($r);
389     }else{
390       $this->error = "Could not connect to LDAP server";
391       return("");
392     }
393   }
395   function rmdir($deletedn)
396   {
397     if($this->hascon){
398       if ($this->reconnect) $this->connect();
399       $start= microtime();
400       $r = @ldap_delete($this->cid, $this->fix($deletedn));
401       $this->error = @ldap_error($this->cid);
402       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
403       return($r ? $r : 0);
404     }else{
405       $this->error = "Could not connect to LDAP server";
406       return("");
407     }
408   }
410   /**
411   *  Function rmdir_recursive
412   *
413   *  Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
414   *  Parameters:  The dn to delete
415   *  GiveBack:    True on sucessfull , 0 in error, and "" when we don't get a ldap conection
416   *
417   */
419   function rmdir_recursive($deletedn)
420   {
421     if($this->hascon){
422       if ($this->reconnect) $this->connect();
423       $delarray= array();
424         
425       /* Get sorted list of dn's to delete */
426       $this->ls ("(objectClass=*)",$deletedn);
427       while ($this->fetch()){
428         $deldn= $this->getDN();
429         $delarray[$deldn]= strlen($deldn);
430       }
431       arsort ($delarray);
432       reset ($delarray);
434       /* Really Delete ALL dn's in subtree */
435       foreach ($delarray as $key => $value){
436         $this->rmdir_recursive($key);
437       }
438       
439       /* Finally Delete own Node */
440       $r = @ldap_delete($this->cid, $this->fix($deletedn));
441       $this->error = @ldap_error($this->cid);
442       return($r ? $r : 0);
443     }else{
444       $this->error = "Could not connect to LDAP server";
445       return("");
446     }
447   }
449   /* Copy given attributes and sub-dns with attributes to destination dn 
450   */
451   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
452   {
453     error_reporting(E_ALL);
454     
455     if($is_first){
456       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
457     }else{
458       if(preg_match("/^ou=/",$sourcedn)){
459         echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
460       }else{
461         $tmp = split(",",$sourcedn);
462         
463         echo "&nbsp;<b>"._("Object").":</b> ";
465         $deststr = @LDAP::fix($destinationdn);
466         if(strlen($deststr) > 96){
467           $deststr = substr($deststr,0,96)."...";
468         }
470         echo $deststr."<br>";
471       }
472     }
474     flush();
475     
476     if($this->hascon){
477       if ($this->reconnect) $this->connect();
479       /* Save base dn */
480       $basedn= $this->basedn;
481       $delarray= array();
482      
483       /* Check if destination entry already exists */
484       $this->cat($destinationdn);
486       if($this->count()){
487         return;
488       }else{
489         
490         $this->clearResult();
492         /* Get source entry */
493         $this->cd($basedn);
494         $this->cat($sourcedn);
495         $attr = $this->fetch();
497         /* Error while fetching object / attribute abort*/
498         if((!$attr) || (count($attr)) ==0) {
499           echo _("Error while fetching source dn - aborted!");
500           return;
501         }
502   
503         /* check if this is a department */
504         if(in_array("organizationalUnit",$attr['objectClass'])){
505           $attr['dn'] = $this->convert($destinationdn);
506           $this->cd($basedn);
507           $this->create_missing_trees($destinationdn);
508           $this->cd($destinationdn);
510           /* If is first entry, append FAIbranch to department entry */
511           if($is_first){
512             $this->cat($destinationdn);
513             $attr= $this->fetch();
515             /* Filter unneeded informations */
516             foreach($attr as $key => $value){
517               if(is_numeric($key)) unset($attr[$key]);
518               if(isset($attr[$key]['count'])){
519                 if(is_array($attr[$key])){
520                   unset($attr[$key]['count']);
521                 }
522               }
523             }
524             
525             unset($attr['count']);
526             unset($attr['dn']);
528             /* Add marking attribute */
529             $attr['objectClass'][] = "FAIbranch";
530             
531             /* Add this entry */
532             $this->modify($attr);
533           }
534         }else{
536           /* If this is no department */
537           foreach($attr as $key => $value){
538             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
539               $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
540               $ei= ldap_first_entry($this->cid, $sr);
541               if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
542                 $attr[$key] = $tmp;
543               }
544             }
546             if(is_numeric($key)) unset($attr[$key]);
547             if(isset($attr[$key]['count'])){
548               if(is_array($attr[$key])){
549                 unset($attr[$key]['count']);
550               }
551             }
552           }
553           unset($attr['count']);
554           unset($attr['dn']);
556           if(!in_array("gosaApplication" , $attr['objectClass'])){
557             if($type=="branch"){
558               $attr['FAIstate'] ="branch";
559             }elseif($type=="freeze"){
560               $attr['FAIstate'] ="freeze";
561             }else{
562               print_red(_("Unknown FAIstate %s"),$type);
563             }
564           }elseif(in_array("gosaApplication",$attr['objectClass'])){
565             $attr['objectClass'][] = "FAIobject";
566             $attr['FAIstate'] = $type;
567           }
569           /* Replace FAIdebianRelease with new release name */
570           if(in_array("FAIpackageList" , $attr['objectClass'])){
571             if($type=="branch"){
572               $attr['FAIstate'] ="branch";
573             }elseif($type=="freeze"){
574               $attr['FAIstate'] ="freeze";
575             }else{
576               print_red(_("Unknown FAIstate %s"),$type);
577             }
578           }
580           /* Add entry */
581           $this->cd($destinationdn);
582           $this->cat($destinationdn);
583           $a = $this->fetch();
584           if(!count($a)){
585             $this->add($attr);
586           }
588           if($this->error != "Success"){
589             /* Some error occured */
590             print "---------------------------------------------";
591             print $this->get_error()."<br>";
592             print $sourcedn."<br>";
593             print $destinationdn."<br>";
594             print_a( $attr);
595             exit();
596           }          
597         }
598       }
600       $this->ls ("(objectClass=*)",$sourcedn);
601       while ($this->fetch()){
602         $deldn= $this->getDN();
603         $delarray[$deldn]= strlen($deldn);
604       }
605       asort ($delarray);
606       reset ($delarray);
608        $depth ++;
609       foreach($delarray as $dn => $bla){
610         if($dn != $destinationdn){
611           $this->cd($basedn);
612           $item = $this->fetch($this->cat($dn));
613           if(!in_array("FAIbranch",$item['objectClass'])){
614             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
615           } 
616         }
617       }
618     }
619     if($is_first){
620       echo "<p class='seperator'>&nbsp;</p>";
621     }
623   }
625   function modify($attrs)
626   {
627     if(count($attrs) == 0){
628       return (0);
629     }
630     if($this->hascon){
631       if ($this->reconnect) $this->connect();
632       $start= microtime();
633       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
634       $this->error = @ldap_error($this->cid);
635       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
636       return($r ? $r : 0);
637     }else{
638       $this->error = "Could not connect to LDAP server";
639       return("");
640     }
641   }
643   function add($attrs)
644   {
645     if($this->hascon){
646       if ($this->reconnect) $this->connect();
647       $start= microtime();
648       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
649       $this->error = @ldap_error($this->cid);
650       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
651       return($r ? $r : 0);
652     }else{
653       $this->error = "Could not connect to LDAP server";
654       return("");
655     }
656   }
658   function create_missing_trees($target)
659   {
660     /* Ignore create_missing trees if the base equals target */
661     if ($target == $this->basedn){
662      return;
663     }
665     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
666     $l= array_reverse(ldap_explode_dn($real_path,0));
667     unset($l['count']);
668     $cdn= $this->basedn;
669     $tag= "";
671     foreach ($l as $part){
672       $cdn= "$part,$cdn";
674       /* Ignore referrals */
675       $found= false;
676       foreach($this->referrals as $ref){
677         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
678         if ($base == $cdn){
679           $found= true;
680           break;
681         }
682       }
683       if ($found){
684         continue;
685       }
687       $this->cat ($cdn);
688       $attrs= $this->fetch();
690       /* Create missing entry? */
691       if (count ($attrs)){
692       
693         /* Catch the tag - if present */
694         if (isset($attrs['gosaUnitTag'][0])){
695           $tag= $attrs['gosaUnitTag'][0];
696         }
698       } else {
699         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
700         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
702         $na= array();
703         switch ($type){
704           case 'ou':
705             if ($tag != ""){
706               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
707               $na["gosaUnitTag"]= $tag;
708             } else {
709               $na["objectClass"]= "organizationalUnit";
710             }
711             $na["ou"]= $param;
712             break;
713           case 'dc':
714             if ($tag != ""){
715               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
716               $na["gosaUnitTag"]= $tag;
717             } else {
718               $na["objectClass"]= array("dcObject", "top", "locality");
719             }
720             $na["dc"]= $param;
721             break;
722           default:
723             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
724             echo $_SESSION['errors'];
725             exit;
726         }
727         $this->cd($cdn);
728         $this->add($na);
729       }
730     }
731   }
733   function recursive_remove()
734   {
735     $delarray= array();
737     /* Get sorted list of dn's to delete */
738     $this->search ("(objectClass=*)");
739     while ($this->fetch()){
740       $deldn= $this->getDN();
741       $delarray[$deldn]= strlen($deldn);
742     }
743     arsort ($delarray);
744     reset ($delarray);
746     /* Delete all dn's in subtree */
747     foreach ($delarray as $key => $value){
748       $this->rmdir($key);
749     }
750   }
752   function get_attribute($dn, $name,$r_array=0)
753   {
754     $data= "";
755     if ($this->reconnect) $this->connect();
756     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
758     /* fill data from LDAP */
759     if ($sr) {
760       $ei= @ldap_first_entry($this->cid, $sr);
761       if ($ei) {
762         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
763           $data= $info[0];
764         }
766       }
767     }
768     if($r_array==0)
769     return ($data);
770     else
771     return ($info);
772   
773   
774   }
775  
778   function get_additional_error()
779   {
780     $error= "";
781     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
782     return ($error);
783   }
785   function get_error()
786   {
787     if ($this->error == 'Success'){
788       return $this->error;
789     } else {
790       $adderror= $this->get_additional_error();
791       if ($adderror != ""){
792         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
793       } else {
794         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
795       }
796       return $error;
797     }
798   }
800   function get_credentials($url, $referrals= NULL)
801   {
802     $ret= array();
803     $url= preg_replace('!\?\?.*$!', '', $url);
804     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
806     if ($referrals == NULL){
807       $referrals= $this->referrals;
808     }
810     if (isset($referrals[$server])){
811       return ($referrals[$server]);
812     } else {
813       $ret['ADMIN']= $this->fix($this->binddn);
814       $ret['PASSWORD']= $this->bindpw;
815     }
817     return ($ret);
818   }
821   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
822   {
823     $display= "";
825     if ($recursive){
826       $this->cd($dn);
827       $this->search("$filter", array('dn'));
828       while ($attrs= $this->fetch()){
829         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
830         $display.= "\n";
831       }
832     } else {
833       $display.= $this->gen_one_entry($dn);
834     }
836     return ($display);
837   }
839 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
840   {
841     $display= "";
843       $this->cd($dn);
844       $this->search("$filter");
846       $i=0;
847       while ($attrs= $this->fetch()){
848         $j=0;
850         foreach ($attributes as $at){
851           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
852           $j++;
853         }
855         $i++;
856       }
858     return ($display);
859   }
862   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
863   {
864     $ret = "";
865     $data = "";
866     if($this->reconnect){
867       $this->connect();
868     }
870     /* Searching Ldap Tree */
871     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
873     /* Get the first entry */   
874     $entry= @ldap_first_entry($this->cid, $sr);
876     /* Get all attributes related to that Objekt */
877     $atts = array();
878     
879     /* Assemble dn */
880     $atts[0]['name']  = "dn";
881     $atts[0]['value'] = array('count' => 1, 0 => $dn);
883     /* Reset index */
884     $i = 1 ; 
885   $identifier = array();
886     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
887     while ($attribute) {
888       $i++;
889       $atts[$i]['name']  = $attribute;
890       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
892       /* Next one */
893       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
894     }
896     foreach($atts as $at)
897     {
898       for ($i= 0; $i<$at['value']['count']; $i++){
900         /* Check if we must encode the data */
901         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
902           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
903         } else {
904           $ret .= $at['name'].": ".$at['value'][$i]."\n";
905         }
906       }
907     }
909     return($ret);
910   }
913   function dn_exists($dn)
914   {
915     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
916   }
917   
920   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
921   {
922     if($this->reconnect) $this->connect();
924     /* First we have to splitt the string ito detect empty lines
925        An empty line indicates an new Entry */
926     $entries = split("\n",$str_attr);
928     $data = "";
929     $cnt = 0; 
930     $current_line = 0;
932     /* Every single line ... */
933     foreach($entries as $entry) {
934       $current_line ++;
936       /* Removing Spaces to .. 
937          .. test if a new entry begins */
938       $tmp  = str_replace(" ","",$data );
940       /* .. prevent empty lines in an entry */
941       $tmp2 = str_replace(" ","",$entry);
943       /* If the Block ends (Empty Line) */
944       if((empty($entry))&&(!empty($tmp))) {
945         /* Add collected lines as a complete block */
946         $all[$cnt] = $data;
947         $cnt ++;
948         $data ="";
949       } else {
951         /* Append lines ... */
952         if(!empty($tmp2)) {
953           /* check if we need base64_decode for this line */
954           if(ereg("::",$tmp2))
955           {
956             $encoded = split("::",$entry);
957             $attr  = $encoded[0];
958             $value = base64_decode($encoded[1]);
959             /* Add linenumber */
960             $data .= $current_line."#".$attr.":".$value."\n";
961           }
962           else
963           {
964             /* Add Linenumber */ 
965             $data .= $current_line."#".$entry."\n";
966           }
967         }
968       }
969     }
971     /* The Data we collected is not in the array all[];
972        For example the Data is stored like this..
974        all[0] = "1#dn : .... \n 
975        2#ObjectType: person \n ...."
976        
977        Now we check every insertblock and try to insert */
978     foreach ( $all as $single) {
979       $lineone = split("\n",$single);  
980       $ndn = split("#", $lineone[0]);
981       $line = $ndn[1];
983       $dnn = split (":",$line);
984       $current_line = $ndn[0];
985       $dn    = $dnn[0];
986       $value = $dnn[1];
988       /* Every block must begin with a dn */
989       if($dn != "dn") {
990         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
991         return -2;  
992       }
994       /* Should we use Modify instead of Add */
995       $usemodify= false;
997       /* Delete before insert */
998       $usermdir= false;
999     
1000       /* The dn address already exists! */
1001       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1003         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1004         return ALREADY_EXISTING_ENTRY;   
1006       } elseif(($this->dn_exists($value))&&($cleanup)){
1008         /* Delete first, then add */
1009         $usermdir = true;        
1011       } elseif(($this->dn_exists($value))&&($overwrite)) {
1012         
1013         /* Modify instead of Add */
1014         $usemodify = true;
1015       }
1016      
1017       /* If we can't Import, return with a file error */
1018       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1019         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1020                         $current_line);
1021         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
1022     }
1024     return (INSERT_OK);
1025   }
1028   /* Imports a single entry */
1029   function import_single_entry($str_attr,$modify,$delete)
1030   {
1031     if($this->reconnect) $this->connect();
1033     $ret = false;
1034     $rows= split("\n",$str_attr);
1035     $data= false;
1037     foreach($rows as $row) {
1038       
1039       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1040          Linenumbers) Linenumbers are use like this 123#attribute : value */
1041       if(!empty($row)) {
1042         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1044           /* We are using line numbers 
1045              Because there is a # before a : */
1046           $tmp1= split("#",$row);
1047           $current_line= $tmp1[0];
1048           $row= $tmp1[1];
1049         }
1051         /* Split the line into  attribute  and value */
1052         $attr   = split(":", $row);
1053         $attr[0]= trim($attr[0]);  /* attribute */
1054         $attr[1]= trim($attr[1]);  /* value */
1056         /* Check for attributes that are used more than once */
1057         if(!isset($data[$attr[0]])) {
1058           $data[$attr[0]]=$attr[1];
1059         } else {
1060           $tmp = $data[$attr[0]];
1062           if(!is_array($tmp)) {
1063             $new[0]=$tmp;
1064             $new[1]=$attr[1];
1065             $datas[$attr[0]]['count']=1;             
1066             $data[$attr[0]]=$new;
1067           } else {
1068             $cnt = $datas[$attr[0]]['count'];           
1069             $cnt ++;
1070             $data[$attr[0]][$cnt]=$attr[1];
1071             $datas[$attr[0]]['count'] = $cnt;
1072           }
1073         }
1074       }
1075     } 
1076     
1077     /* If dn is an index of data, we should try to insert the data */
1078     if(isset($data['dn'])) {
1079       /* Creating Entry */
1080       $this->cd($data['dn']);
1082       /* Delete existing entry */
1083       if($delete){
1084         $this->rmdir($data['dn']);
1085       }
1086       
1087       /* Create missing trees */
1088       $this->create_missing_trees($data['dn']);
1089       unset($data['dn']);
1090       
1091       /* If entry exists use modify */
1092       if(!$modify){
1093         $ret = $this->add($data);
1094       } else {
1095         $ret = $this->modify($data);
1096       }
1097     }
1099     return($ret);
1100   }
1102   
1103   function importcsv($str)
1104   {
1105     $lines = split("\n",$str);
1106     foreach($lines as $line)
1107     {
1108       /* continue if theres a comment */
1109       if(substr(trim($line),0,1)=="#"){
1110         continue;
1111       }
1113       $line= str_replace ("\t\t","\t",$line);
1114       $line= str_replace ("\t"  ,"," ,$line);
1115       echo $line;
1117       $cells = split(",",$line )  ;
1118       $linet= str_replace ("\t\t",",",$line);
1119       $cells = split("\t",$line);
1120       $count = count($cells);  
1121     }
1123   }
1124   
1125   function get_objectclasses()
1126   {
1127           $objectclasses = array();
1128         
1129           # Get base to look for schema 
1130           $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1131           $attr = @ldap_get_entries($this->cid,$sr);
1132           if (!isset($attr[0]['subschemasubentry'][0])){
1133             return array();
1134           }
1135         
1136           # Get list of objectclasses
1137           $nb= $attr[0]['subschemasubentry'][0];
1138           $objectclasses= array();
1139           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1140           $attrs= ldap_get_entries($this->cid,$sr);
1141           if (!isset($attrs[0])){
1142             return array();
1143           }
1144           foreach ($attrs[0]['objectclasses'] as $val){
1145             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1146             if ($name != $val){
1147               $objectclasses[$name]= $val;
1148             }
1149           }
1150           
1151           return $objectclasses;
1152   }
1155   function log($string)
1156   {
1157     $cfg= $_SESSION['config'];
1158     if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1159         syslog (LOG_INFO, $string);
1160     }
1161   }
1166 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1167 ?>