Code

Updated 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             if(!in_array("FAIobject",$attr['objectClass'])){
566               $attr['objectClass'][] = "FAIobject";
567             }
568             $attr['FAIstate'] = $type;
569           }
571           /* Replace FAIdebianRelease with new release name */
572           if(in_array("FAIpackageList" , $attr['objectClass'])){
573             $attr['FAIdebianRelease'] = $destinationName;
574             if($type=="branch"){
575               $attr['FAIstate'] ="branch";
576             }elseif($type=="freeze"){
577               $attr['FAIstate'] ="freeze";
578             }else{
579               print_red(_("Unknown FAIstate %s"),$type);
580             }
581           }
583           /* Add entry */
584           $this->cd($destinationdn);
585           $this->cat($destinationdn);
586           $a = $this->fetch();
587           if(!count($a)){
588             $this->add($attr);
589           }
591           if($this->error != "Success"){
592             /* Some error occured */
593             print "---------------------------------------------";
594             print $this->get_error()."<br>";
595             print $sourcedn."<br>";
596             print $destinationdn."<br>";
597             print_a( $attr);
598             exit();
599           }          
600         }
601       }
603       echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
605       $this->ls ("(objectClass=*)",$sourcedn);
606       while ($this->fetch()){
607         $deldn= $this->getDN();
608         $delarray[$deldn]= strlen($deldn);
609       }
610       asort ($delarray);
611       reset ($delarray);
613        $depth ++;
614       foreach($delarray as $dn => $bla){
615         if($dn != $destinationdn){
616           $this->cd($basedn);
617           $item = $this->fetch($this->cat($dn));
618           if(!in_array("FAIbranch",$item['objectClass'])){
619             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
620           } 
621         }
622       }
623     }
624     if($is_first){
625       echo "<p class='seperator'>&nbsp;</p>";
626     }
628   }
630   function modify($attrs)
631   {
632     if(count($attrs) == 0){
633       return (0);
634     }
635     if($this->hascon){
636       if ($this->reconnect) $this->connect();
637       $start= microtime();
638       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
639       $this->error = @ldap_error($this->cid);
640       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
641       return($r ? $r : 0);
642     }else{
643       $this->error = "Could not connect to LDAP server";
644       return("");
645     }
646   }
648   function add($attrs)
649   {
650     if($this->hascon){
651       if ($this->reconnect) $this->connect();
652       $start= microtime();
653       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
654       $this->error = @ldap_error($this->cid);
655       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
656       return($r ? $r : 0);
657     }else{
658       $this->error = "Could not connect to LDAP server";
659       return("");
660     }
661   }
664   function create_missing_trees($target)
665   {
666     global $config;
668     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
670     if ($target == $this->basedn){
671       $l= array("dummy");
672     } else {
673       $l= array_reverse(gosa_ldap_explode_dn($real_path));
674     }
675     unset($l['count']);
676     $cdn= $this->basedn;
677     $tag= "";
679     /* Load schema if available... */
680     $classes= $this->get_objectclasses();
682     foreach ($l as $part){
683       if ($part != "dummy"){
684         $cdn= "$part,$cdn";
685       }
687       /* Ignore referrals */
688       $found= false;
689       foreach($this->referrals as $ref){
690         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
691         if ($base == $cdn){
692           $found= true;
693           break;
694         }
695       }
696       if ($found){
697         continue;
698       }
700       $this->cat ($cdn);
701       $attrs= $this->fetch();
703       /* Create missing entry? */
704       if (count ($attrs)){
705         /* Catch the tag - if present */
706         if (isset($attrs['gosaUnitTag'][0])){
707           $tag= $attrs['gosaUnitTag'][0];
708         }
710       } else {
711         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
712         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
714         $na= array();
716         /* Automatic or traditional? */
717         if(count($classes)){
719           /* Get name of first matching objectClass */
720           $ocname= "";
721           foreach($classes as $class){
722             if (isset($class['MUST']) && $class['MUST'] == "$type"){
724               /* Look for first classes that is structural... */
725               if (isset($class['STRUCTURAL'])){
726                 $ocname= $class['NAME'];
727                 break;
728               }
730               /* Look for classes that are auxiliary... */
731               if (isset($class['AUXILIARY'])){
732                 $ocname= $class['NAME'];
733               }
734             }
735           }
737           /* Bail out, if we've nothing to do... */
738           if ($ocname == ""){
739             print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
740             echo $_SESSION['errors'];
741             exit;
742           }
744           /* Assemble_entry */
745           if ($tag != ""){
746             $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
747           } else {
748             $na['objectClass']= array($ocname);
749           }
750           if (isset($classes[$ocname]['AUXILIARY'])){
751             $na['objectClass'][]= $classes[$ocname]['SUP'];
752           }
753           if ($type == "dc"){
754             /* This is bad actually, but - tell me a better way? */
755             $na['objectClass'][]= 'locality';
756           }
757           $na[$type]= $param;
758           if (is_array($classes[$ocname]['MUST'])){
759             foreach($classes[$ocname]['MUST'] as $attr){
760               $na[$attr]= "filled";
761             }
762           }
764         } else {
766           /* Use alternative add... */
767           switch ($type){
768             case 'ou':
769               if ($tag != ""){
770                 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
771                 $na["gosaUnitTag"]= $tag;
772               } else {
773                 $na["objectClass"]= "organizationalUnit";
774               }
775               $na["ou"]= $param;
776               break;
777             case 'dc':
778               if ($tag != ""){
779                 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
780                 $na["gosaUnitTag"]= $tag;
781               } else {
782                 $na["objectClass"]= array("dcObject", "top", "locality");
783               }
784               $na["dc"]= $param;
785               break;
786             default:
787               print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
788               echo $_SESSION['errors'];
789               exit;
790           }
792         }
793         $this->cd($cdn);
794         $this->add($na);
795         show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
796         if (!preg_match('/success/i', $this->error)){
797           return FALSE;
798         }
799       }
800     }
802     return TRUE;
803   }
806   function create_missing_trees_old($target)
807   {
808     /* Ignore create_missing trees if the base equals target */
809     if ($target == $this->basedn){
810      return;
811     }
813     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
814     $tmp = ldap_explode_dn($real_path,0);
815     if(!$tmp){
816       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)));
817       return;
818     }
820     $l= array_reverse($tmp);
821     unset($l['count']);
822     $cdn= $this->basedn;
823     $tag= "";
825     foreach ($l as $part){
826       $cdn= "$part,$cdn";
828       /* Ignore referrals */
829       $found= false;
830       foreach($this->referrals as $ref){
831         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
832         if ($base == $cdn){
833           $found= true;
834           break;
835         }
836       }
837       if ($found){
838         continue;
839       }
841       $this->cat ($cdn);
842       $attrs= $this->fetch();
844       /* Create missing entry? */
845       if (count ($attrs)){
846       
847         /* Catch the tag - if present */
848         if (isset($attrs['gosaUnitTag'][0])){
849           $tag= $attrs['gosaUnitTag'][0];
850         }
852       } else {
853         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
854         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
856         $na= array();
857         switch ($type){
858           case 'ou':
859             if ($tag != ""){
860               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
861               $na["gosaUnitTag"]= $tag;
862             } else {
863               $na["objectClass"]= "organizationalUnit";
864             }
865             $na["ou"]= $param;
866             break;
867           case 'dc':
868             if ($tag != ""){
869               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
870               $na["gosaUnitTag"]= $tag;
871             } else {
872               $na["objectClass"]= array("dcObject", "top", "locality");
873             }
874             $na["dc"]= $param;
875             break;
876           default:
877             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
878             echo $_SESSION['errors'];
879             exit;
880         }
881         $this->cd($cdn);
882         $this->add($na);
883       }
884     }
885   }
887   function recursive_remove()
888   {
889     $delarray= array();
891     /* Get sorted list of dn's to delete */
892     $this->search ("(objectClass=*)");
893     while ($this->fetch()){
894       $deldn= $this->getDN();
895       $delarray[$deldn]= strlen($deldn);
896     }
897     arsort ($delarray);
898     reset ($delarray);
900     /* Delete all dn's in subtree */
901     foreach ($delarray as $key => $value){
902       $this->rmdir($key);
903     }
904   }
906   function get_attribute($dn, $name,$r_array=0)
907   {
908     $data= "";
909     if ($this->reconnect) $this->connect();
910     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
912     /* fill data from LDAP */
913     if ($sr) {
914       $ei= @ldap_first_entry($this->cid, $sr);
915       if ($ei) {
916         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
917           $data= $info[0];
918         }
920       }
921     }
922     if($r_array==0)
923     return ($data);
924     else
925     return ($info);
926   
927   
928   }
929  
932   function get_additional_error()
933   {
934     $error= "";
935     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
936     return ($error);
937   }
939   function get_error()
940   {
941     if ($this->error == 'Success'){
942       return $this->error;
943     } else {
944       $adderror= $this->get_additional_error();
945       if ($adderror != ""){
946         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
947       } else {
948         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
949       }
950       return $error;
951     }
952   }
954   function get_credentials($url, $referrals= NULL)
955   {
956     $ret= array();
957     $url= preg_replace('!\?\?.*$!', '', $url);
958     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
960     if ($referrals == NULL){
961       $referrals= $this->referrals;
962     }
964     if (isset($referrals[$server])){
965       return ($referrals[$server]);
966     } else {
967       $ret['ADMIN']= $this->fix($this->binddn);
968       $ret['PASSWORD']= $this->bindpw;
969     }
971     return ($ret);
972   }
975   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
976   {
977     $display= "";
979     if ($recursive){
980       $this->cd($dn);
981       $this->search("$filter", array('dn'));
982       while ($attrs= $this->fetch()){
983         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
984         $display.= "\n";
985       }
986     } else {
987       $display.= $this->gen_one_entry($dn);
988     }
990     return ($display);
991   }
993 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
994   {
995     $display= "";
997       $this->cd($dn);
998       $this->search("$filter");
1000       $i=0;
1001       while ($attrs= $this->fetch()){
1002         $j=0;
1004         foreach ($attributes as $at){
1005           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1006           $j++;
1007         }
1009         $i++;
1010       }
1012     return ($display);
1013   }
1016   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1017   {
1018     $ret = "";
1019     $data = "";
1020     if($this->reconnect){
1021       $this->connect();
1022     }
1024     /* Searching Ldap Tree */
1025     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1027     /* Get the first entry */   
1028     $entry= @ldap_first_entry($this->cid, $sr);
1030     /* Get all attributes related to that Objekt */
1031     $atts = array();
1032     
1033     /* Assemble dn */
1034     $atts[0]['name']  = "dn";
1035     $atts[0]['value'] = array('count' => 1, 0 => $dn);
1037     /* Reset index */
1038     $i = 1 ; 
1039   $identifier = array();
1040     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1041     while ($attribute) {
1042       $i++;
1043       $atts[$i]['name']  = $attribute;
1044       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1046       /* Next one */
1047       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1048     }
1050     foreach($atts as $at)
1051     {
1052       for ($i= 0; $i<$at['value']['count']; $i++){
1054         /* Check if we must encode the data */
1055         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1056           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1057         } else {
1058           $ret .= $at['name'].": ".$at['value'][$i]."\n";
1059         }
1060       }
1061     }
1063     return($ret);
1064   }
1067   function dn_exists($dn)
1068   {
1069     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1070   }
1071   
1074   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1075   {
1076     if($this->reconnect) $this->connect();
1078     /* First we have to splitt the string ito detect empty lines
1079        An empty line indicates an new Entry */
1080     $entries = split("\n",$str_attr);
1082     $data = "";
1083     $cnt = 0; 
1084     $current_line = 0;
1086     /* Every single line ... */
1087     foreach($entries as $entry) {
1088       $current_line ++;
1090       /* Removing Spaces to .. 
1091          .. test if a new entry begins */
1092       $tmp  = str_replace(" ","",$data );
1094       /* .. prevent empty lines in an entry */
1095       $tmp2 = str_replace(" ","",$entry);
1097       /* If the Block ends (Empty Line) */
1098       if((empty($entry))&&(!empty($tmp))) {
1099         /* Add collected lines as a complete block */
1100         $all[$cnt] = $data;
1101         $cnt ++;
1102         $data ="";
1103       } else {
1105         /* Append lines ... */
1106         if(!empty($tmp2)) {
1107           /* check if we need base64_decode for this line */
1108           if(ereg("::",$tmp2))
1109           {
1110             $encoded = split("::",$entry);
1111             $attr  = $encoded[0];
1112             $value = base64_decode($encoded[1]);
1113             /* Add linenumber */
1114             $data .= $current_line."#".$attr.":".$value."\n";
1115           }
1116           else
1117           {
1118             /* Add Linenumber */ 
1119             $data .= $current_line."#".$entry."\n";
1120           }
1121         }
1122       }
1123     }
1125     /* The Data we collected is not in the array all[];
1126        For example the Data is stored like this..
1128        all[0] = "1#dn : .... \n 
1129        2#ObjectType: person \n ...."
1130        
1131        Now we check every insertblock and try to insert */
1132     foreach ( $all as $single) {
1133       $lineone = split("\n",$single);  
1134       $ndn = split("#", $lineone[0]);
1135       $line = $ndn[1];
1137       $dnn = split (":",$line,2);
1138       $current_line = $ndn[0];
1139       $dn    = $dnn[0];
1140       $value = $dnn[1];
1142       /* Every block must begin with a dn */
1143       if($dn != "dn") {
1144         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1145         return -2;  
1146       }
1148       /* Should we use Modify instead of Add */
1149       $usemodify= false;
1151       /* Delete before insert */
1152       $usermdir= false;
1153     
1154       /* The dn address already exists! */
1155       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1157         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1158         return ALREADY_EXISTING_ENTRY;   
1160       } elseif(($this->dn_exists($value))&&($cleanup)){
1162         /* Delete first, then add */
1163         $usermdir = true;        
1165       } elseif(($this->dn_exists($value))&&($overwrite)) {
1166         
1167         /* Modify instead of Add */
1168         $usemodify = true;
1169       }
1170      
1171       /* If we can't Import, return with a file error */
1172       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1173         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1174                         $current_line);
1175         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
1176     }
1178     return (INSERT_OK);
1179   }
1182   /* Imports a single entry */
1183   function import_single_entry($str_attr,$modify,$delete)
1184   {
1185     if($this->reconnect) $this->connect();
1187     $ret = false;
1188     $rows= split("\n",$str_attr);
1189     $data= false;
1191     foreach($rows as $row) {
1192       
1193       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1194          Linenumbers) Linenumbers are use like this 123#attribute : value */
1195       if(!empty($row)) {
1196         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1198           /* We are using line numbers 
1199              Because there is a # before a : */
1200           $tmp1= split("#",$row);
1201           $current_line= $tmp1[0];
1202           $row= $tmp1[1];
1203         }
1205         /* Split the line into  attribute  and value */
1206         $attr   = split(":", $row,2);
1207         $attr[0]= trim($attr[0]);  /* attribute */
1208         $attr[1]= trim($attr[1]);  /* value */
1210         /* Check for attributes that are used more than once */
1211         if(!isset($data[$attr[0]])) {
1212           $data[$attr[0]]=$attr[1];
1213         } else {
1214           $tmp = $data[$attr[0]];
1216           if(!is_array($tmp)) {
1217             $new[0]=$tmp;
1218             $new[1]=$attr[1];
1219             $datas[$attr[0]]['count']=1;             
1220             $data[$attr[0]]=$new;
1221           } else {
1222             $cnt = $datas[$attr[0]]['count'];           
1223             $cnt ++;
1224             $data[$attr[0]][$cnt]=$attr[1];
1225             $datas[$attr[0]]['count'] = $cnt;
1226           }
1227         }
1228       }
1229     } 
1230     
1231     /* If dn is an index of data, we should try to insert the data */
1232     if(isset($data['dn'])) {
1233       /* Creating Entry */
1234       $this->cd($data['dn']);
1236       /* Delete existing entry */
1237       if($delete){
1238         $this->rmdir($data['dn']);
1239       }
1240       
1241       /* Create missing trees */
1242       $this->create_missing_trees($data['dn']);
1243       unset($data['dn']);
1244       
1245       /* If entry exists use modify */
1246       if(!$modify){
1247         $ret = $this->add($data);
1248       } else {
1249         $ret = $this->modify($data);
1250       }
1251     }
1253     return($ret);
1254   }
1256   
1257   function importcsv($str)
1258   {
1259     $lines = split("\n",$str);
1260     foreach($lines as $line)
1261     {
1262       /* continue if theres a comment */
1263       if(substr(trim($line),0,1)=="#"){
1264         continue;
1265       }
1267       $line= str_replace ("\t\t","\t",$line);
1268       $line= str_replace ("\t"  ,"," ,$line);
1269       echo $line;
1271       $cells = split(",",$line )  ;
1272       $linet= str_replace ("\t\t",",",$line);
1273       $cells = split("\t",$line);
1274       $count = count($cells);  
1275     }
1277   }
1278   
1279   function get_objectclasses_old()
1280   {
1281     $objectclasses = array();
1283           # Get base to look for schema 
1284           $sr           = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1285           $attr         = @ldap_get_entries($this->cid,$sr);
1287           if (!isset($attr[0]['subschemasubentry'][0])){
1288       $this->error  = @ldap_error($this->cid);
1289       gosa_log($this->get_error());
1290       return array();
1291           }
1292         
1293           # Get list of objectclasses
1294           $nb= $attr[0]['subschemasubentry'][0];
1295           $objectclasses= array();
1296           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1297           $attrs= ldap_get_entries($this->cid,$sr);
1298           if (!isset($attrs[0])){
1299             return array();
1300           }
1301           foreach ($attrs[0]['objectclasses'] as $val){
1302             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1303             if ($name != $val){
1304               $objectclasses[$name]= $val;
1305             }
1306           }
1307           
1308           return $objectclasses;
1309   }
1312   function get_objectclasses()
1313   {
1314     $objectclasses = array();
1316     if(!isset($ithis->config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
1317       return($objectclasses);
1318     }
1320 # Get base to look for schema
1321     $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1322     if(!$sr){
1323       $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1324     }
1326     $attr = @ldap_get_entries($this->cid,$sr);
1327     if (!isset($attr[0]['subschemasubentry'][0])){
1328       return array();
1329     }
1331     /* Get list of objectclasses and fill array */
1332     $nb= $attr[0]['subschemasubentry'][0];
1333     $objectclasses= array();
1334     $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1335     $attrs= ldap_get_entries($this->cid,$sr);
1336     if (!isset($attrs[0])){
1337       return array();
1338     }
1339     foreach ($attrs[0]['objectclasses'] as $val){
1340       if (preg_match('/^[0-9]+$/', $val)){
1341         continue;
1342       }
1343       $name= "OID";
1344       $pattern= split(' ', $val);
1345       $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1346       $objectclasses[$ocname]= array();
1348       foreach($pattern as $chunk){
1349         switch($chunk){
1351           case '(':
1352             $value= "";
1353             break;
1355           case ')': if ($name != ""){
1356                       $objectclasses[$ocname][$name]= $this->value2container($value);
1357                     }
1358                     $name= "";
1359                     $value= "";
1360                     break;
1362           case 'NAME':
1363           case 'DESC':
1364           case 'SUP':
1365           case 'STRUCTURAL':
1366           case 'ABSTRACT':
1367           case 'AUXILIARY':
1368           case 'MUST':
1369           case 'MAY':
1370                     if ($name != ""){
1371                       $objectclasses[$ocname][$name]= $this->value2container($value);
1372                     }
1373                     $name= $chunk;
1374                     $value= "";
1375                     break;
1377           default:  $value.= $chunk." ";
1378         }
1379       }
1381     }
1383     return $objectclasses;
1384   }
1386   function value2container($value)
1387   {
1388     /* Set emtpy values to "true" only */
1389     if (preg_match('/^\s*$/', $value)){
1390       return true;
1391     }
1393     /* Remove ' and " if needed */
1394     $value= preg_replace('/^[\'"]/', '', $value);
1395     $value= preg_replace('/[\'"] *$/', '', $value);
1397     /* Convert to array if $ is inside... */
1398     if (preg_match('/\$/', $value)){
1399       $container= preg_split('/\s*\$\s*/', $value);
1400     } else {
1401       $container= chop($value);
1402     }
1404     return ($container);
1405   }
1407   function log($string)
1408   {
1409     if (isset($_SESSION['config'])){
1410       $cfg= $_SESSION['config'];
1411       if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1412         syslog (LOG_INFO, $string);
1413       }
1414     }
1415   }
1416   
1417   /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1418   function getCn($dn){
1419     $simple= split(",", $dn);
1421     foreach($simple as $piece) {
1422       $partial= split("=", $piece);
1424       if($partial[0] == "cn"){
1425         return $partial[1];
1426       }
1427     }
1429   }
1431   function get_naming_contexts($server, $admin= "", $password= "")
1432   {
1433     /* Build LDAP connection */
1434     $ds= ldap_connect ($server);
1435     if (!$ds) {
1436       die ("Can't bind to LDAP. No check possible!");
1437     }
1438     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1439     $r= ldap_bind ($ds, $admin, $password);
1441     /* Get base to look for naming contexts */
1442     $sr  = @ldap_read ($ds, "", "objectClass=*", array("+"));
1443     $attr= @ldap_get_entries($ds,$sr);
1445     return ($attr[0]['namingcontexts']);
1446   }
1450 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1451 ?>