Code

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