Code

Added logging to get_objectclasses
[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             $attr['FAIdebianRelease'] = $destinationName;
572             if($type=="branch"){
573               $attr['FAIstate'] ="branch";
574             }elseif($type=="freeze"){
575               $attr['FAIstate'] ="freeze";
576             }else{
577               print_red(_("Unknown FAIstate %s"),$type);
578             }
579           }
581           /* Add entry */
582           $this->cd($destinationdn);
583           $this->cat($destinationdn);
584           $a = $this->fetch();
585           if(!count($a)){
586             $this->add($attr);
587           }
589           if($this->error != "Success"){
590             /* Some error occured */
591             print "---------------------------------------------";
592             print $this->get_error()."<br>";
593             print $sourcedn."<br>";
594             print $destinationdn."<br>";
595             print_a( $attr);
596             exit();
597           }          
598         }
599       }
601       $this->ls ("(objectClass=*)",$sourcedn);
602       while ($this->fetch()){
603         $deldn= $this->getDN();
604         $delarray[$deldn]= strlen($deldn);
605       }
606       asort ($delarray);
607       reset ($delarray);
609        $depth ++;
610       foreach($delarray as $dn => $bla){
611         if($dn != $destinationdn){
612           $this->cd($basedn);
613           $item = $this->fetch($this->cat($dn));
614           if(!in_array("FAIbranch",$item['objectClass'])){
615             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
616           } 
617         }
618       }
619     }
620     if($is_first){
621       echo "<p class='seperator'>&nbsp;</p>";
622     }
624   }
626   function modify($attrs)
627   {
628     if(count($attrs) == 0){
629       return (0);
630     }
631     if($this->hascon){
632       if ($this->reconnect) $this->connect();
633       $start= microtime();
634       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
635       $this->error = @ldap_error($this->cid);
636       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
637       return($r ? $r : 0);
638     }else{
639       $this->error = "Could not connect to LDAP server";
640       return("");
641     }
642   }
644   function add($attrs)
645   {
646     if($this->hascon){
647       if ($this->reconnect) $this->connect();
648       $start= microtime();
649       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
650       $this->error = @ldap_error($this->cid);
651       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
652       return($r ? $r : 0);
653     }else{
654       $this->error = "Could not connect to LDAP server";
655       return("");
656     }
657   }
659   function create_missing_trees($target)
660   {
661     /* Ignore create_missing trees if the base equals target */
662     if ($target == $this->basedn){
663      return;
664     }
666     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
667     $tmp = ldap_explode_dn($real_path,0);
668     if(!$tmp){
669       print_red(sprintf(_("The referral url '%s' is missing the ldap base. It should look like this 'ldap://server:port/base'."),$this->fix($this->basedn)));
670       return;
671     }
673     $l= array_reverse($tmp);
674     unset($l['count']);
675     $cdn= $this->basedn;
676     $tag= "";
678     foreach ($l as $part){
679       $cdn= "$part,$cdn";
681       /* Ignore referrals */
682       $found= false;
683       foreach($this->referrals as $ref){
684         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
685         if ($base == $cdn){
686           $found= true;
687           break;
688         }
689       }
690       if ($found){
691         continue;
692       }
694       $this->cat ($cdn);
695       $attrs= $this->fetch();
697       /* Create missing entry? */
698       if (count ($attrs)){
699       
700         /* Catch the tag - if present */
701         if (isset($attrs['gosaUnitTag'][0])){
702           $tag= $attrs['gosaUnitTag'][0];
703         }
705       } else {
706         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
707         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
709         $na= array();
710         switch ($type){
711           case 'ou':
712             if ($tag != ""){
713               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
714               $na["gosaUnitTag"]= $tag;
715             } else {
716               $na["objectClass"]= "organizationalUnit";
717             }
718             $na["ou"]= $param;
719             break;
720           case 'dc':
721             if ($tag != ""){
722               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
723               $na["gosaUnitTag"]= $tag;
724             } else {
725               $na["objectClass"]= array("dcObject", "top", "locality");
726             }
727             $na["dc"]= $param;
728             break;
729           default:
730             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
731             echo $_SESSION['errors'];
732             exit;
733         }
734         $this->cd($cdn);
735         $this->add($na);
736       }
737     }
738   }
740   function recursive_remove()
741   {
742     $delarray= array();
744     /* Get sorted list of dn's to delete */
745     $this->search ("(objectClass=*)");
746     while ($this->fetch()){
747       $deldn= $this->getDN();
748       $delarray[$deldn]= strlen($deldn);
749     }
750     arsort ($delarray);
751     reset ($delarray);
753     /* Delete all dn's in subtree */
754     foreach ($delarray as $key => $value){
755       $this->rmdir($key);
756     }
757   }
759   function get_attribute($dn, $name,$r_array=0)
760   {
761     $data= "";
762     if ($this->reconnect) $this->connect();
763     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
765     /* fill data from LDAP */
766     if ($sr) {
767       $ei= @ldap_first_entry($this->cid, $sr);
768       if ($ei) {
769         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
770           $data= $info[0];
771         }
773       }
774     }
775     if($r_array==0)
776     return ($data);
777     else
778     return ($info);
779   
780   
781   }
782  
785   function get_additional_error()
786   {
787     $error= "";
788     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
789     return ($error);
790   }
792   function get_error()
793   {
794     if ($this->error == 'Success'){
795       return $this->error;
796     } else {
797       $adderror= $this->get_additional_error();
798       if ($adderror != ""){
799         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
800       } else {
801         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
802       }
803       return $error;
804     }
805   }
807   function get_credentials($url, $referrals= NULL)
808   {
809     $ret= array();
810     $url= preg_replace('!\?\?.*$!', '', $url);
811     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
813     if ($referrals == NULL){
814       $referrals= $this->referrals;
815     }
817     if (isset($referrals[$server])){
818       return ($referrals[$server]);
819     } else {
820       $ret['ADMIN']= $this->fix($this->binddn);
821       $ret['PASSWORD']= $this->bindpw;
822     }
824     return ($ret);
825   }
828   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
829   {
830     $display= "";
832     if ($recursive){
833       $this->cd($dn);
834       $this->search("$filter", array('dn'));
835       while ($attrs= $this->fetch()){
836         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
837         $display.= "\n";
838       }
839     } else {
840       $display.= $this->gen_one_entry($dn);
841     }
843     return ($display);
844   }
846 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
847   {
848     $display= "";
850       $this->cd($dn);
851       $this->search("$filter");
853       $i=0;
854       while ($attrs= $this->fetch()){
855         $j=0;
857         foreach ($attributes as $at){
858           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
859           $j++;
860         }
862         $i++;
863       }
865     return ($display);
866   }
869   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
870   {
871     $ret = "";
872     $data = "";
873     if($this->reconnect){
874       $this->connect();
875     }
877     /* Searching Ldap Tree */
878     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
880     /* Get the first entry */   
881     $entry= @ldap_first_entry($this->cid, $sr);
883     /* Get all attributes related to that Objekt */
884     $atts = array();
885     
886     /* Assemble dn */
887     $atts[0]['name']  = "dn";
888     $atts[0]['value'] = array('count' => 1, 0 => $dn);
890     /* Reset index */
891     $i = 1 ; 
892   $identifier = array();
893     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
894     while ($attribute) {
895       $i++;
896       $atts[$i]['name']  = $attribute;
897       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
899       /* Next one */
900       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
901     }
903     foreach($atts as $at)
904     {
905       for ($i= 0; $i<$at['value']['count']; $i++){
907         /* Check if we must encode the data */
908         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
909           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
910         } else {
911           $ret .= $at['name'].": ".$at['value'][$i]."\n";
912         }
913       }
914     }
916     return($ret);
917   }
920   function dn_exists($dn)
921   {
922     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
923   }
924   
927   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
928   {
929     if($this->reconnect) $this->connect();
931     /* First we have to splitt the string ito detect empty lines
932        An empty line indicates an new Entry */
933     $entries = split("\n",$str_attr);
935     $data = "";
936     $cnt = 0; 
937     $current_line = 0;
939     /* Every single line ... */
940     foreach($entries as $entry) {
941       $current_line ++;
943       /* Removing Spaces to .. 
944          .. test if a new entry begins */
945       $tmp  = str_replace(" ","",$data );
947       /* .. prevent empty lines in an entry */
948       $tmp2 = str_replace(" ","",$entry);
950       /* If the Block ends (Empty Line) */
951       if((empty($entry))&&(!empty($tmp))) {
952         /* Add collected lines as a complete block */
953         $all[$cnt] = $data;
954         $cnt ++;
955         $data ="";
956       } else {
958         /* Append lines ... */
959         if(!empty($tmp2)) {
960           /* check if we need base64_decode for this line */
961           if(ereg("::",$tmp2))
962           {
963             $encoded = split("::",$entry);
964             $attr  = $encoded[0];
965             $value = base64_decode($encoded[1]);
966             /* Add linenumber */
967             $data .= $current_line."#".$attr.":".$value."\n";
968           }
969           else
970           {
971             /* Add Linenumber */ 
972             $data .= $current_line."#".$entry."\n";
973           }
974         }
975       }
976     }
978     /* The Data we collected is not in the array all[];
979        For example the Data is stored like this..
981        all[0] = "1#dn : .... \n 
982        2#ObjectType: person \n ...."
983        
984        Now we check every insertblock and try to insert */
985     foreach ( $all as $single) {
986       $lineone = split("\n",$single);  
987       $ndn = split("#", $lineone[0]);
988       $line = $ndn[1];
990       $dnn = split (":",$line);
991       $current_line = $ndn[0];
992       $dn    = $dnn[0];
993       $value = $dnn[1];
995       /* Every block must begin with a dn */
996       if($dn != "dn") {
997         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
998         return -2;  
999       }
1001       /* Should we use Modify instead of Add */
1002       $usemodify= false;
1004       /* Delete before insert */
1005       $usermdir= false;
1006     
1007       /* The dn address already exists! */
1008       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1010         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1011         return ALREADY_EXISTING_ENTRY;   
1013       } elseif(($this->dn_exists($value))&&($cleanup)){
1015         /* Delete first, then add */
1016         $usermdir = true;        
1018       } elseif(($this->dn_exists($value))&&($overwrite)) {
1019         
1020         /* Modify instead of Add */
1021         $usemodify = true;
1022       }
1023      
1024       /* If we can't Import, return with a file error */
1025       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1026         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1027                         $current_line);
1028         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
1029     }
1031     return (INSERT_OK);
1032   }
1035   /* Imports a single entry */
1036   function import_single_entry($str_attr,$modify,$delete)
1037   {
1038     if($this->reconnect) $this->connect();
1040     $ret = false;
1041     $rows= split("\n",$str_attr);
1042     $data= false;
1044     foreach($rows as $row) {
1045       
1046       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1047          Linenumbers) Linenumbers are use like this 123#attribute : value */
1048       if(!empty($row)) {
1049         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1051           /* We are using line numbers 
1052              Because there is a # before a : */
1053           $tmp1= split("#",$row);
1054           $current_line= $tmp1[0];
1055           $row= $tmp1[1];
1056         }
1058         /* Split the line into  attribute  and value */
1059         $attr   = split(":", $row);
1060         $attr[0]= trim($attr[0]);  /* attribute */
1061         $attr[1]= trim($attr[1]);  /* value */
1063         /* Check for attributes that are used more than once */
1064         if(!isset($data[$attr[0]])) {
1065           $data[$attr[0]]=$attr[1];
1066         } else {
1067           $tmp = $data[$attr[0]];
1069           if(!is_array($tmp)) {
1070             $new[0]=$tmp;
1071             $new[1]=$attr[1];
1072             $datas[$attr[0]]['count']=1;             
1073             $data[$attr[0]]=$new;
1074           } else {
1075             $cnt = $datas[$attr[0]]['count'];           
1076             $cnt ++;
1077             $data[$attr[0]][$cnt]=$attr[1];
1078             $datas[$attr[0]]['count'] = $cnt;
1079           }
1080         }
1081       }
1082     } 
1083     
1084     /* If dn is an index of data, we should try to insert the data */
1085     if(isset($data['dn'])) {
1086       /* Creating Entry */
1087       $this->cd($data['dn']);
1089       /* Delete existing entry */
1090       if($delete){
1091         $this->rmdir($data['dn']);
1092       }
1093       
1094       /* Create missing trees */
1095       $this->create_missing_trees($data['dn']);
1096       unset($data['dn']);
1097       
1098       /* If entry exists use modify */
1099       if(!$modify){
1100         $ret = $this->add($data);
1101       } else {
1102         $ret = $this->modify($data);
1103       }
1104     }
1106     return($ret);
1107   }
1109   
1110   function importcsv($str)
1111   {
1112     $lines = split("\n",$str);
1113     foreach($lines as $line)
1114     {
1115       /* continue if theres a comment */
1116       if(substr(trim($line),0,1)=="#"){
1117         continue;
1118       }
1120       $line= str_replace ("\t\t","\t",$line);
1121       $line= str_replace ("\t"  ,"," ,$line);
1122       echo $line;
1124       $cells = split(",",$line )  ;
1125       $linet= str_replace ("\t\t",",",$line);
1126       $cells = split("\t",$line);
1127       $count = count($cells);  
1128     }
1130   }
1131   
1132   function get_objectclasses()
1133   {
1134           $objectclasses = array();
1135         
1136           # Get base to look for schema 
1137           $sr           = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1138           $attr         = @ldap_get_entries($this->cid,$sr);
1139     $this->error  = @ldap_error($this->cid);
1141     gosa_log($this->get_error());
1143           if (!isset($attr[0]['subschemasubentry'][0])){
1144             return array();
1145           }
1146         
1147           # Get list of objectclasses
1148           $nb= $attr[0]['subschemasubentry'][0];
1149           $objectclasses= array();
1150           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1151           $attrs= ldap_get_entries($this->cid,$sr);
1152           if (!isset($attrs[0])){
1153             return array();
1154           }
1155           foreach ($attrs[0]['objectclasses'] as $val){
1156             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1157             if ($name != $val){
1158               $objectclasses[$name]= $val;
1159             }
1160           }
1161           
1162           return $objectclasses;
1163   }
1166   function log($string)
1167   {
1168     if (isset($_SESSION['config'])){
1169       $cfg= $_SESSION['config'];
1170       if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1171         syslog (LOG_INFO, $string);
1172       }
1173     }
1174   }
1175   
1176   /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1177   function getCn($dn){
1178     $simple= split(",", $dn);
1180     foreach($simple as $piece) {
1181       $partial= split("=", $piece);
1183       if($partial[0] == "cn"){
1184         return $partial[1];
1185       }
1186     }
1188   }
1193 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1194 ?>