Code

- Update of the french locale for 2.5.14
[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       \22 => TO
63       \"  => TO
64       \+  => PL
65       (   => OB
66       )   => CB
67       /   => SL                                                                  */
68   function convert($dn)
69   {
70     if (SPECIALS_OVERRIDE == TRUE){
71       $tmp= preg_replace(array("/\\\\,/", "/\\\\2C/", "/\(/", "/\)/", "/\//", "/\\\\22/", '/\\\\"/', "/\\\\3D/", "/\\\\2B/", '/\\\\+/'),
72                            array("\001CO", "\001CO", "\001OB", "\001CB", "\001SL", "\001TO", "\001TO", "\001GL", "\001PL", "\001PL"),
73                            $dn);
74       return (preg_replace('/,\s+/', ',', $tmp));
75     } else {
76       return ($dn);
77     }
78   }
81   /* Function to fix all problematic characters inside a DN by replacing \001XX
82      codes to their original values. See "convert" for mor information. 
83      ',' characters are always expanded to \, (not \2C), since all tested LDAP
84      servers seem to take it the correct way.                                  */
85   function fix($dn)
86   {
87     if (SPECIALS_OVERRIDE == TRUE){
88       return (preg_replace(array("/\001CO/", "/\001OB/", "/\001CB/", "/\001SL/", "/\001TO/", "/\001PL/", "/\001GL/"),
89                            array("\,", "(", ")", "/", '\"', "\+", "="),
90                            $dn));
91     } else {
92       return ($dn);
93     }
94   }
97   function connect()
98   {
99     $this->hascon=false;
100     $this->reconnect=false;
101     if ($this->cid= @ldap_connect($this->hostname)) {
102       @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
103       if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
104         @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
105         @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
106       }
107       if (function_exists("ldap_start_tls") && $this->tls){
108         @ldap_start_tls($this->cid);
109       }
111       $this->error = "No Error";
112       if ($bid = @ldap_bind($this->cid, $this->fix($this->binddn), $this->bindpw)) {
113         $this->error = "Success";
114         $this->hascon=true;
115       } else {
116         if ($this->reconnect){
117           if ($this->error != "Success"){
118             $this->error = "Could not rebind to " . $this->binddn;
119           }
120         } else {
121           $this->error = "Could not bind to " . $this->binddn;
122         }
123       }
124     } else {
125       $this->error = "Could not connect to LDAP server";
126     }
127   }
129   function rebind($ldap, $referral)
130   {
131     $credentials= $this->get_credentials($referral);
132     if (@ldap_bind($ldap, $this->fix($credentials['ADMIN']), $credentials['PASSWORD'])) {
133       $this->error = "Success";
134       $this->hascon=true;
135       $this->reconnect= true;
136       return (0);
137     } else {
138       $this->error = "Could not bind to " . $credentials['ADMIN'];
139       return NULL;
140     }
141   }
143   function reconnect()
144   {
145     if ($this->reconnect){
146       @ldap_unbind($this->cid);
147       $this->cid = NULL;
148     }
149   }
151   function unbind()
152   {
153     @ldap_unbind($this->cid);
154     $this->cid = NULL;
155   }
157   function disconnect()
158   {
159     if($this->hascon){
160       @ldap_close($this->cid);
161       $this->hascon=false;
162     }
163   }
165   function cd($dir)
166   {
167     if ($dir == "..")
168       $this->basedn = $this->getParentDir();
169     else
170       $this->basedn = $this->convert($dir);
171   }
173   function getParentDir($basedn = "")
174   {
175     if ($basedn=="")
176       $basedn = $this->basedn;
177     else
178       $basedn = $this->convert($this->basedn);
179     return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
180   }
182   function search($filter, $attrs= array())
183   {
184     if($this->hascon){
185       if ($this->reconnect) $this->connect();
187       $start = microtime();
188    
189       $this->clearResult();
190       $this->sr = @ldap_search($this->cid, $this->fix($this->basedn), $filter, $attrs);
191       $this->error = @ldap_error($this->cid);
192       $this->resetResult();
193       $this->hasres=true;
194    
195       /* Check if query took longer as specified in max_ldap_query_time */
196       if($this->max_ldap_query_time){
197         $diff = get_MicroTimeDiff($start,microtime());
198         if($diff > $this->max_ldap_query_time){
199           print_red(sprintf(_("The LDAP server is slow (%.2fs for the last query). This may be responsible for performance breakdowns."),$diff)) ;
200         }
201       }
203       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=search('".$this->fix($this->basedn)."', '$filter')");
205       return($this->sr);
206     }else{
207       $this->error = "Could not connect to LDAP server";
208       return("");
209     }
210   }
212   function ls($filter = "(objectclass=*)", $basedn = "",$attrs = array("*"))
213   {
214     if($this->hascon){
215       if ($this->reconnect) $this->connect();
216       $this->clearResult();
217       if ($basedn == "")
218         $basedn = $this->basedn;
219       else
220         $basedn= $this->convert($basedn);
221   
222       $start = microtime();
224       $this->sr = @ldap_list($this->cid, $this->fix($basedn), $filter,$attrs);
225       $this->error = @ldap_error($this->cid);
226       $this->resetResult();
227       $this->hasres=true;
229        /* Check if query took longer as specified in max_ldap_query_time */
230       if($this->max_ldap_query_time){
231         $diff = get_MicroTimeDiff($start,microtime());
232         if($diff > $this->max_ldap_query_time){
233           print_red(sprintf(_("The ldapserver is answering very slow (%.2f), this may be responsible for performance breakdowns."),$diff)) ;
234         }
235       }
237       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=ls('".$this->fix($basedn)."', '$filter')");
239       return($this->sr);
240     }else{
241       $this->error = "Could not connect to LDAP server";
242       return("");
243     }
244   }
246   function cat($dn,$attrs= array("*"))
247   {
248     if($this->hascon){
249       if ($this->reconnect) $this->connect();
250       $start = microtime();
251       $this->clearResult();
252       $filter = "(objectclass=*)";
253       $this->sr = @ldap_read($this->cid, $this->fix($dn), $filter,$attrs);
254       $this->error = @ldap_error($this->cid);
255       $this->resetResult();
256       $this->hasres=true;
257       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=cat('".$this->fix($dn)."')");
258       return($this->sr);
259     }else{
260       $this->error = "Could not connect to LDAP server";
261       return("");
262     }
263   }
265   function set_size_limit($size)
266   {
267     /* Ignore zero settings */
268     if ($size == 0){
269       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
270     }
271     if($this->hascon){
272       @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
273     } else {
274       $this->error = "Could not connect to LDAP server";
275     }
276   }
278   function fetch()
279   {
280     $att= array();
281     if($this->hascon){
282       if($this->hasres){
283         if ($this->start == 0)
284         {
285           $this->start = 1;
286           $this->re= @ldap_first_entry($this->cid, $this->sr);
287         } else {
288           $this->re= @ldap_next_entry($this->cid, $this->re);
289         }
290         if ($this->re)
291         {
292           $att= @ldap_get_attributes($this->cid, $this->re);
293           $att['dn']= trim($this->convert(@ldap_get_dn($this->cid, $this->re)));
294         }
295         $this->error = @ldap_error($this->cid);
296         if (!isset($att)){
297           $att= array();
298         }
299         return($att);
300       }else{
301         $this->error = "Perform a Fetch with no Search";
302         return("");
303       }
304     }else{
305       $this->error = "Could not connect to LDAP server";
306       return("");
307     }
308   }
310   function resetResult()
311   {
312     $this->start = 0;
313   }
315   function clearResult()
316   {
317     if($this->hasres){
318       $this->hasres = false;
319       @ldap_free_result($this->sr);
320     }
321   }
323   function getDN()
324   {
325     if($this->hascon){
326       if($this->hasres){
328         if(!$this->re)
329           {
330           $this->error = "Perform a Fetch with no valid Result";
331           }
332           else
333           {
334           $rv = @ldap_get_dn($this->cid, $this->re);
335         
336           $this->error = @ldap_error($this->cid);
337           return(trim($this->convert($rv)));
338            }
339       }else{
340         $this->error = "Perform a Fetch with no Search";
341         return("");
342       }
343     }else{
344       $this->error = "Could not connect to LDAP server";
345       return("");
346     }
347   }
349   function count()
350   {
351     if($this->hascon){
352       if($this->hasres){
353         $rv = @ldap_count_entries($this->cid, $this->sr);
354         $this->error = @ldap_error($this->cid);
355         return($rv);
356       }else{
357         $this->error = "Perform a Fetch with no Search";
358         return("");
359       }
360     }else{
361       $this->error = "Could not connect to LDAP server";
362       return("");
363     }
364   }
366   function rm($attrs = "", $dn = "")
367   {
368     if($this->hascon){
369       if ($this->reconnect) $this->connect();
370       if ($dn == "")
371         $dn = $this->basedn;
373       $r = @ldap_mod_del($this->cid, $this->fix($dn), $attrs);
374       $this->error = @ldap_error($this->cid);
375       return($r);
376     }else{
377       $this->error = "Could not connect to LDAP server";
378       return("");
379     }
380   }
382   function rename($attrs, $dn = "")
383   {
384     if($this->hascon){
385       if ($this->reconnect) $this->connect();
386       if ($dn == "")
387         $dn = $this->basedn;
389       $r = @ldap_mod_replace($this->cid, $this->fix($dn), $attrs);
390       $this->error = @ldap_error($this->cid);
391       return($r);
392     }else{
393       $this->error = "Could not connect to LDAP server";
394       return("");
395     }
396   }
398   function rmdir($deletedn)
399   {
400     if($this->hascon){
401       if ($this->reconnect) $this->connect();
402       $start= microtime();
403       $r = @ldap_delete($this->cid, $this->fix($deletedn));
404       $this->error = @ldap_error($this->cid);
405       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=delete('".$this->fix($deletedn)."')");
406       return($r ? $r : 0);
407     }else{
408       $this->error = "Could not connect to LDAP server";
409       return("");
410     }
411   }
413   /**
414   *  Function rmdir_recursive
415   *
416   *  Description: Based in recursive_remove, adding two thing: full subtree remove, and delete own node.
417   *  Parameters:  The dn to delete
418   *  GiveBack:    True on sucessfull , 0 in error, and "" when we don't get a ldap conection
419   *
420   */
422   function rmdir_recursive($deletedn)
423   {
424     if($this->hascon){
425       if ($this->reconnect) $this->connect();
426       $delarray= array();
427         
428       /* Get sorted list of dn's to delete */
429       $this->ls ("(objectClass=*)",$deletedn);
430       while ($this->fetch()){
431         $deldn= $this->getDN();
432         $delarray[$deldn]= strlen($deldn);
433       }
434       arsort ($delarray);
435       reset ($delarray);
437       /* Really Delete ALL dn's in subtree */
438       foreach ($delarray as $key => $value){
439         $this->rmdir_recursive($key);
440       }
441       
442       /* Finally Delete own Node */
443       $r = @ldap_delete($this->cid, $this->fix($deletedn));
444       $this->error = @ldap_error($this->cid);
445       return($r ? $r : 0);
446     }else{
447       $this->error = "Could not connect to LDAP server";
448       return("");
449     }
450   }
452   /* Copy given attributes and sub-dns with attributes to destination dn 
453   */
454   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
455   {
456     error_reporting(E_ALL);
457     
458     if($is_first){
459       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".@LDAP::fix($sourcedn)."</i>")."</h2>";
460     }else{
461       if(preg_match("/^ou=/",$sourcedn)){
462         echo "<h3>"._("Processing")." <i>".@LDAP::fix($destinationdn)."</i></h3>";
463       }else{
464         $tmp = split(",",$sourcedn);
465         
466         echo "&nbsp;<b>"._("Object").":</b> ";
468         $deststr = @LDAP::fix($destinationdn);
469         if(strlen($deststr) > 96){
470           $deststr = substr($deststr,0,96)."...";
471         }
473         echo $deststr."<br>";
474       }
475     }
477     flush();
478     
479     if($this->hascon){
480       if ($this->reconnect) $this->connect();
482       /* Save base dn */
483       $basedn= $this->basedn;
484       $delarray= array();
485      
486       /* Check if destination entry already exists */
487       $this->cat($destinationdn);
489       if($this->count()){
490         return;
491       }else{
492         
493         $this->clearResult();
495         /* Get source entry */
496         $this->cd($basedn);
497         $this->cat($sourcedn);
498         $attr = $this->fetch();
500         /* Error while fetching object / attribute abort*/
501         if((!$attr) || (count($attr)) ==0) {
502           echo _("Error while fetching source dn - aborted!");
503           return;
504         }
505   
506         /* check if this is a department */
507         if(in_array("organizationalUnit",$attr['objectClass'])){
508           $attr['dn'] = $this->convert($destinationdn);
509           $this->cd($basedn);
510           $this->create_missing_trees($destinationdn);
511           $this->cd($destinationdn);
513           /* If is first entry, append FAIbranch to department entry */
514           if($is_first){
515             $this->cat($destinationdn);
516             $attr= $this->fetch();
518             /* Filter unneeded informations */
519             foreach($attr as $key => $value){
520               if(is_numeric($key)) unset($attr[$key]);
521               if(isset($attr[$key]['count'])){
522                 if(is_array($attr[$key])){
523                   unset($attr[$key]['count']);
524                 }
525               }
526             }
527             
528             unset($attr['count']);
529             unset($attr['dn']);
531             /* Add marking attribute */
532             $attr['objectClass'][] = "FAIbranch";
533             
534             /* Add this entry */
535             $this->modify($attr);
536           }
537         }else{
539           /* If this is no department */
540           foreach($attr as $key => $value){
541             if(in_array($key ,array("FAItemplateFile","FAIscript", "gotoLogonScript", "gosaApplicationIcon"))){
542               $sr= ldap_read($this->cid, $this->fix($sourcedn), "$key=*", array($key));
543               $ei= ldap_first_entry($this->cid, $sr);
544               if ($tmp= @ldap_get_values_len($this->cid, $ei,$key)){
545                 $attr[$key] = $tmp;
546               }
547             }
549             if(is_numeric($key)) unset($attr[$key]);
550             if(isset($attr[$key]['count'])){
551               if(is_array($attr[$key])){
552                 unset($attr[$key]['count']);
553               }
554             }
555           }
556           unset($attr['count']);
557           unset($attr['dn']);
559           if(!in_array("gosaApplication" , $attr['objectClass'])){
560             if($type=="branch"){
561               $attr['FAIstate'] ="branch";
562             }elseif($type=="freeze"){
563               $attr['FAIstate'] ="freeze";
564             }else{
565               print_red(_("Unknown FAIstate %s"),$type);
566             }
567           }elseif(in_array("gosaApplication",$attr['objectClass'])){
568             if(!in_array("FAIobject",$attr['objectClass'])){
569               $attr['objectClass'][] = "FAIobject";
570             }
571             $attr['FAIstate'] = $type;
572           }
574           /* Replace FAIdebianRelease with new release name */
575           if(in_array("FAIpackageList" , $attr['objectClass'])){
576             $attr['FAIdebianRelease'] = $destinationName;
577             if($type=="branch"){
578               $attr['FAIstate'] ="branch";
579             }elseif($type=="freeze"){
580               $attr['FAIstate'] ="freeze";
581             }else{
582               print_red(_("Unknown FAIstate %s"),$type);
583             }
584           }
586           /* Add entry */
587           $this->cd($destinationdn);
588           $this->cat($destinationdn);
589           $a = $this->fetch();
590           if(!count($a)){
591             $this->add($attr);
592           }
594           if($this->error != "Success"){
595             /* Some error occurred */
596             print "---------------------------------------------";
597             print $this->get_error()."<br>";
598             print $sourcedn."<br>";
599             print $destinationdn."<br>";
600             print_a( $attr);
601             exit();
602           }          
603         }
604       }
606       echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
608       $this->ls ("(objectClass=*)",$sourcedn);
609       while ($this->fetch()){
610         $deldn= $this->getDN();
611         $delarray[$deldn]= strlen($deldn);
612       }
613       asort ($delarray);
614       reset ($delarray);
616        $depth ++;
617       foreach($delarray as $dn => $bla){
618         if($dn != $destinationdn){
619           $this->cd($basedn);
620           $item = $this->fetch($this->cat($dn));
621           if(!in_array("FAIbranch",$item['objectClass'])){
622             $this->copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
623           } 
624         }
625       }
626     }
627     if($is_first){
628       echo "<p class='seperator'>&nbsp;</p>";
629     }
631   }
633   function modify($attrs)
634   {
635     if(count($attrs) == 0){
636       return (0);
637     }
638     if($this->hascon){
639       if ($this->reconnect) $this->connect();
640       $start= microtime();
641       $r = @ldap_modify($this->cid, $this->fix($this->basedn), $attrs);
642       $this->error = @ldap_error($this->cid);
643       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=modify('$this->basedn')");
644       return($r ? $r : 0);
645     }else{
646       $this->error = "Could not connect to LDAP server";
647       return("");
648     }
649   }
651   function add($attrs)
652   {
653     if($this->hascon){
654       if ($this->reconnect) $this->connect();
655       $start= microtime();
656       $r = @ldap_add($this->cid, $this->fix($this->basedn), $attrs);
657       $this->error = @ldap_error($this->cid);
658       $this->log("LDAP operation: time=".get_MicroTimeDiff($start,microtime())." operation=add('$this->basedn')");
659       return($r ? $r : 0);
660     }else{
661       $this->error = "Could not connect to LDAP server";
662       return("");
663     }
664   }
667   function create_missing_trees($target)
668   {
669     global $config;
671     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
673     if ($target == $this->basedn){
674       $l= array("dummy");
675     } else {
676       $l= array_reverse(gosa_ldap_explode_dn($real_path));
677     }
678     unset($l['count']);
679     $cdn= $this->basedn;
680     $tag= "";
682     /* Load schema if available... */
683     $classes= $this->get_objectclasses();
685     foreach ($l as $part){
686       if ($part != "dummy"){
687         $cdn= "$part,$cdn";
688       }
690       /* Ignore referrals */
691       $found= false;
692       foreach($this->referrals as $ref){
693         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
694         if ($base == $cdn){
695           $found= true;
696           break;
697         }
698       }
699       if ($found){
700         continue;
701       }
703       $this->cat ($cdn);
704       $attrs= $this->fetch();
706       /* Create missing entry? */
707       if (count ($attrs)){
708         /* Catch the tag - if present */
709         if (isset($attrs['gosaUnitTag'][0])){
710           $tag= $attrs['gosaUnitTag'][0];
711         }
713       } else {
714         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
715         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
717         $na= array();
719         /* Automatic or traditional? */
720         if(count($classes)){
722           /* Get name of first matching objectClass */
723           $ocname= "";
724           foreach($classes as $class){
725             if (isset($class['MUST']) && $class['MUST'] == "$type"){
727               /* Look for first classes that is structural... */
728               if (isset($class['STRUCTURAL'])){
729                 $ocname= $class['NAME'];
730                 break;
731               }
733               /* Look for classes that are auxiliary... */
734               if (isset($class['AUXILIARY'])){
735                 $ocname= $class['NAME'];
736               }
737             }
738           }
740           /* Bail out, if we've nothing to do... */
741           if ($ocname == ""){
742             print_red(sprintf(_("Autocreation of subtree failed. No objectClass found for attribute '%s'."), $type));
743             echo $_SESSION['errors'];
744             exit;
745           }
747           /* Assemble_entry */
748           if ($tag != ""){
749             $na['objectClass']= array($ocname, "gosaAdministrativeUnitTag");
750             $na["gosaUnitTag"]= $tag;
751           } else {
752             $na['objectClass']= array($ocname);
753           }
754           if (isset($classes[$ocname]['AUXILIARY'])){
755             $na['objectClass'][]= $classes[$ocname]['SUP'];
756           }
757           if ($type == "dc"){
758             /* This is bad actually, but - tell me a better way? */
759             $na['objectClass'][]= 'locality';
760           }
761           $na[$type]= $param;
762           if (is_array($classes[$ocname]['MUST'])){
763             foreach($classes[$ocname]['MUST'] as $attr){
764               $na[$attr]= "filled";
765             }
766           }
768         } else {
770           /* Use alternative add... */
771           switch ($type){
772             case 'ou':
773               if ($tag != ""){
774                 $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
775                 $na["gosaUnitTag"]= $tag;
776               } else {
777                 $na["objectClass"]= "organizationalUnit";
778               }
779               $na["ou"]= $param;
780               break;
781             case 'dc':
782               if ($tag != ""){
783                 $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
784                 $na["gosaUnitTag"]= $tag;
785               } else {
786                 $na["objectClass"]= array("dcObject", "top", "locality");
787               }
788               $na["dc"]= $param;
789               break;
790             default:
791               print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
792               echo $_SESSION['errors'];
793               exit;
794           }
796         }
797         $this->cd($cdn);
798         $this->add($na);
799         show_ldap_error($this->get_error(), sprintf(_("Creating subtree '%s' failed."),$cdn));
800         if (!preg_match('/success/i', $this->error)){
801           return FALSE;
802         }
803       }
804     }
806     return TRUE;
807   }
810   function create_missing_trees_old($target)
811   {
812     /* Ignore create_missing trees if the base equals target */
813     if ($target == $this->basedn){
814      return;
815     }
817     $real_path= substr($target, 0, strlen($target) - strlen($this->basedn) -1 );
818     $tmp = ldap_explode_dn($real_path,0);
819     if(!$tmp){
820       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)));
821       return;
822     }
824     $l= array_reverse($tmp);
825     unset($l['count']);
826     $cdn= $this->basedn;
827     $tag= "";
829     foreach ($l as $part){
830       $cdn= "$part,$cdn";
832       /* Ignore referrals */
833       $found= false;
834       foreach($this->referrals as $ref){
835         $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
836         if ($base == $cdn){
837           $found= true;
838           break;
839         }
840       }
841       if ($found){
842         continue;
843       }
845       $this->cat ($cdn);
846       $attrs= $this->fetch();
848       /* Create missing entry? */
849       if (count ($attrs)){
850       
851         /* Catch the tag - if present */
852         if (isset($attrs['gosaUnitTag'][0])){
853           $tag= $attrs['gosaUnitTag'][0];
854         }
856       } else {
857         $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
858         $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
860         $na= array();
861         switch ($type){
862           case 'ou':
863             if ($tag != ""){
864               $na["objectClass"]= array("organizationalUnit", "gosaAdministrativeUnitTag");
865               $na["gosaUnitTag"]= $tag;
866             } else {
867               $na["objectClass"]= "organizationalUnit";
868             }
869             $na["ou"]= $param;
870             break;
871           case 'dc':
872             if ($tag != ""){
873               $na["objectClass"]= array("dcObject", "top", "locality", "gosaAdministrativeUnitTag");
874               $na["gosaUnitTag"]= $tag;
875             } else {
876               $na["objectClass"]= array("dcObject", "top", "locality");
877             }
878             $na["dc"]= $param;
879             break;
880           default:
881             print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
882             echo $_SESSION['errors'];
883             exit;
884         }
885         $this->cd($cdn);
886         $this->add($na);
887       }
888     }
889   }
891   function recursive_remove()
892   {
893     $delarray= array();
895     /* Get sorted list of dn's to delete */
896     $this->search ("(objectClass=*)");
897     while ($this->fetch()){
898       $deldn= $this->getDN();
899       $delarray[$deldn]= strlen($deldn);
900     }
901     arsort ($delarray);
902     reset ($delarray);
904     /* Delete all dn's in subtree */
905     foreach ($delarray as $key => $value){
906       $this->rmdir($key);
907     }
908   }
910   function get_attribute($dn, $name,$r_array=0)
911   {
912     $data= "";
913     if ($this->reconnect) $this->connect();
914     $sr= @ldap_read($this->cid, $this->fix($dn), "objectClass=*", array("$name"));
916     /* fill data from LDAP */
917     if ($sr) {
918       $ei= @ldap_first_entry($this->cid, $sr);
919       if ($ei) {
920         if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
921           $data= $info[0];
922         }
924       }
925     }
926     if($r_array==0)
927     return ($data);
928     else
929     return ($info);
930   
931   
932   }
933  
936   function get_additional_error()
937   {
938     $error= "";
939     @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
940     return ($error);
941   }
943   function get_error()
944   {
945     if ($this->error == 'Success'){
946       return $this->error;
947     } else {
948       $adderror= $this->get_additional_error();
949       if ($adderror != ""){
950         $error= $this->error." (".$this->get_additional_error().", ".sprintf(_("while operating on '%s' using LDAP server '%s'"), $this->basedn, $this->hostname).")";
951       } else {
952         $error= $this->error." (".sprintf(_("while operating on LDAP server %s"), $this->hostname).")";
953       }
954       return $error;
955     }
956   }
958   function get_credentials($url, $referrals= NULL)
959   {
960     $ret= array();
961     $url= preg_replace('!\?\?.*$!', '', $url);
962     $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
964     if ($referrals == NULL){
965       $referrals= $this->referrals;
966     }
968     if (isset($referrals[$server])){
969       return ($referrals[$server]);
970     } else {
971       $ret['ADMIN']= $this->fix($this->binddn);
972       $ret['PASSWORD']= $this->bindpw;
973     }
975     return ($ret);
976   }
979   function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
980   {
981     $display= "";
983     if ($recursive){
984       $this->cd($dn);
985       $this->search("$filter", array('dn'));
986       while ($attrs= $this->fetch()){
987         $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
988         $display.= "\n";
989       }
990     } else {
991       $display.= $this->gen_one_entry($dn);
992     }
994     return ($display);
995   }
997 function gen_xls ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE,$r_array=0)
998   {
999     $display= "";
1001       $this->cd($dn);
1002       $this->search("$filter");
1004       $i=0;
1005       while ($attrs= $this->fetch()){
1006         $j=0;
1008         foreach ($attributes as $at){
1009           $display[$i][$j]= $this->get_attribute($attrs['dn'], $at,$r_array);
1010           $j++;
1011         }
1013         $i++;
1014       }
1016     return ($display);
1017   }
1020   function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
1021   {
1022     $ret = "";
1023     $data = "";
1024     if($this->reconnect){
1025       $this->connect();
1026     }
1028     /* Searching Ldap Tree */
1029     $sr= @ldap_read($this->cid, $this->fix($dn), $filter, $name);
1031     /* Get the first entry */   
1032     $entry= @ldap_first_entry($this->cid, $sr);
1034     /* Get all attributes related to that Objekt */
1035     $atts = array();
1036     
1037     /* Assemble dn */
1038     $atts[0]['name']  = "dn";
1039     $atts[0]['value'] = array('count' => 1, 0 => $dn);
1041     /* Reset index */
1042     $i = 1 ; 
1043   $identifier = array();
1044     $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
1045     while ($attribute) {
1046       $i++;
1047       $atts[$i]['name']  = $attribute;
1048       $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
1050       /* Next one */
1051       $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
1052     }
1054     foreach($atts as $at)
1055     {
1056       for ($i= 0; $i<$at['value']['count']; $i++){
1058         /* Check if we must encode the data */
1059         if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
1060           $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
1061         } else {
1062           $ret .= $at['name'].": ".$at['value'][$i]."\n";
1063         }
1064       }
1065     }
1067     return($ret);
1068   }
1071   function dn_exists($dn)
1072   {
1073     return @ldap_list($this->cid, $this->fix($dn), "(objectClass=*)", array("objectClass"));
1074   }
1075   
1078   function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
1079   {
1080     if($this->reconnect) $this->connect();
1082     /* First we have to splitt the string ito detect empty lines
1083        An empty line indicates an new Entry */
1084     $entries = split("\n",$str_attr);
1086     $data = "";
1087     $cnt = 0; 
1088     $current_line = 0;
1090     /* Every single line ... */
1091     foreach($entries as $entry) {
1092       $current_line ++;
1094       /* Removing Spaces to .. 
1095          .. test if a new entry begins */
1096       $tmp  = str_replace(" ","",$data );
1098       /* .. prevent empty lines in an entry */
1099       $tmp2 = str_replace(" ","",$entry);
1101       /* If the Block ends (Empty Line) */
1102       if((empty($entry))&&(!empty($tmp))) {
1103         /* Add collected lines as a complete block */
1104         $all[$cnt] = $data;
1105         $cnt ++;
1106         $data ="";
1107       } else {
1109         /* Append lines ... */
1110         if(!empty($tmp2)) {
1111           /* check if we need base64_decode for this line */
1112           if(ereg("::",$tmp2))
1113           {
1114             $encoded = split("::",$entry);
1115             $attr  = $encoded[0];
1116             $value = base64_decode($encoded[1]);
1117             /* Add linenumber */
1118             $data .= $current_line."#".$attr.":".$value."\n";
1119           }
1120           else
1121           {
1122             /* Add Linenumber */ 
1123             $data .= $current_line."#".$entry."\n";
1124           }
1125         }
1126       }
1127     }
1129     /* The Data we collected is not in the array all[];
1130        For example the Data is stored like this..
1132        all[0] = "1#dn : .... \n 
1133        2#ObjectType: person \n ...."
1134        
1135        Now we check every insertblock and try to insert */
1136     foreach ( $all as $single) {
1137       $lineone = split("\n",$single);  
1138       $ndn = split("#", $lineone[0]);
1139       $line = $ndn[1];
1141       $dnn = split (":",$line,2);
1142       $current_line = $ndn[0];
1143       $dn    = $dnn[0];
1144       $value = $dnn[1];
1146       /* Every block must begin with a dn */
1147       if($dn != "dn") {
1148         $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"), $line, $current_line);
1149         return -2;  
1150       }
1152       /* Should we use Modify instead of Add */
1153       $usemodify= false;
1155       /* Delete before insert */
1156       $usermdir= false;
1157     
1158       /* The dn address already exists! */
1159       if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
1161         $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
1162         return ALREADY_EXISTING_ENTRY;   
1164       } elseif(($this->dn_exists($value))&&($cleanup)){
1166         /* Delete first, then add */
1167         $usermdir = true;        
1169       } elseif(($this->dn_exists($value))&&($overwrite)) {
1170         
1171         /* Modify instead of Add */
1172         $usemodify = true;
1173       }
1174      
1175       /* If we can't Import, return with a file error */
1176       if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
1177         $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
1178                         $current_line);
1179         return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
1180     }
1182     return (INSERT_OK);
1183   }
1186   /* Imports a single entry */
1187   function import_single_entry($str_attr,$modify,$delete)
1188   {
1189     if($this->reconnect) $this->connect();
1191     $ret = false;
1192     $rows= split("\n",$str_attr);
1193     $data= false;
1195     foreach($rows as $row) {
1196       
1197       /* Check if we use Linenumbers (when import_complete_ldif is called we use
1198          Linenumbers) Linenumbers are use like this 123#attribute : value */
1199       if(!empty($row)) {
1200         if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
1202           /* We are using line numbers 
1203              Because there is a # before a : */
1204           $tmp1= split("#",$row);
1205           $current_line= $tmp1[0];
1206           $row= $tmp1[1];
1207         }
1209         /* Split the line into  attribute  and value */
1210         $attr   = split(":", $row,2);
1211         $attr[0]= trim($attr[0]);  /* attribute */
1212         $attr[1]= trim($attr[1]);  /* value */
1214         /* Check for attributes that are used more than once */
1215         if(!isset($data[$attr[0]])) {
1216           $data[$attr[0]]=$attr[1];
1217         } else {
1218           $tmp = $data[$attr[0]];
1220           if(!is_array($tmp)) {
1221             $new[0]=$tmp;
1222             $new[1]=$attr[1];
1223             $datas[$attr[0]]['count']=1;             
1224             $data[$attr[0]]=$new;
1225           } else {
1226             $cnt = $datas[$attr[0]]['count'];           
1227             $cnt ++;
1228             $data[$attr[0]][$cnt]=$attr[1];
1229             $datas[$attr[0]]['count'] = $cnt;
1230           }
1231         }
1232       }
1233     } 
1234     
1235     /* If dn is an index of data, we should try to insert the data */
1236     if(isset($data['dn'])) {
1237       /* Creating Entry */
1238       $this->cd($data['dn']);
1240       /* Delete existing entry */
1241       if($delete){
1242         $this->rmdir($data['dn']);
1243       }
1244       
1245       /* Create missing trees */
1246       $this->create_missing_trees($data['dn']);
1247       unset($data['dn']);
1248       
1249       /* If entry exists use modify */
1250       if(!$modify){
1251         $ret = $this->add($data);
1252       } else {
1253         $ret = $this->modify($data);
1254       }
1255     }
1257     return($ret);
1258   }
1260   
1261   function importcsv($str)
1262   {
1263     $lines = split("\n",$str);
1264     foreach($lines as $line)
1265     {
1266       /* continue if theres a comment */
1267       if(substr(trim($line),0,1)=="#"){
1268         continue;
1269       }
1271       $line= str_replace ("\t\t","\t",$line);
1272       $line= str_replace ("\t"  ,"," ,$line);
1273       echo $line;
1275       $cells = split(",",$line )  ;
1276       $linet= str_replace ("\t\t",",",$line);
1277       $cells = split("\t",$line);
1278       $count = count($cells);  
1279     }
1281   }
1282   
1283   function get_objectclasses_old()
1284   {
1285     $objectclasses = array();
1287           # Get base to look for schema 
1288           $sr           = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1289           $attr         = @ldap_get_entries($this->cid,$sr);
1291           if (!isset($attr[0]['subschemasubentry'][0])){
1292       $this->error  = @ldap_error($this->cid);
1293       gosa_log($this->get_error());
1294       return array();
1295           }
1296         
1297           # Get list of objectclasses
1298           $nb= $attr[0]['subschemasubentry'][0];
1299           $objectclasses= array();
1300           $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1301           $attrs= ldap_get_entries($this->cid,$sr);
1302           if (!isset($attrs[0])){
1303             return array();
1304           }
1305           foreach ($attrs[0]['objectclasses'] as $val){
1306             $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1307             if ($name != $val){
1308               $objectclasses[$name]= $val;
1309             }
1310           }
1311           
1312           return $objectclasses;
1313   }
1316   function get_objectclasses()
1317   {
1318     global $config;
1319     $objectclasses = array();
1321     if(isset($config) && preg_match("/config/i",get_class($config))){
1322       if(!isset($config->data['MAIN']['SCHEMA_CHECK']) || !preg_match("/true/i",$config->data['MAIN']['SCHEMA_CHECK'])){
1323         return($objectclasses);
1324       }
1325     }
1327 # Get base to look for schema
1328     $sr = @ldap_read ($this->cid, NULL, "objectClass=*", array("subschemaSubentry"));
1329     if(!$sr){
1330       $sr = @ldap_read ($this->cid, "", "objectClass=*", array("subschemaSubentry"));
1331     }
1333     $attr = @ldap_get_entries($this->cid,$sr);
1334     if (!isset($attr[0]['subschemasubentry'][0])){
1335       return array();
1336     }
1338     /* Get list of objectclasses and fill array */
1339     $nb= $attr[0]['subschemasubentry'][0];
1340     $objectclasses= array();
1341     $sr= ldap_read ($this->cid, $nb, "objectClass=*", array("objectclasses"));
1342     $attrs= ldap_get_entries($this->cid,$sr);
1343     if (!isset($attrs[0])){
1344       return array();
1345     }
1346     foreach ($attrs[0]['objectclasses'] as $val){
1347       if (preg_match('/^[0-9]+$/', $val)){
1348         continue;
1349       }
1350       $name= "OID";
1351       $pattern= split(' ', $val);
1352       $ocname= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
1353       $objectclasses[$ocname]= array();
1355       foreach($pattern as $chunk){
1356         switch($chunk){
1358           case '(':
1359             $value= "";
1360             break;
1362           case ')': if ($name != ""){
1363                       $objectclasses[$ocname][$name]= $this->value2container($value);
1364                     }
1365                     $name= "";
1366                     $value= "";
1367                     break;
1369           case 'NAME':
1370           case 'DESC':
1371           case 'SUP':
1372           case 'STRUCTURAL':
1373           case 'ABSTRACT':
1374           case 'AUXILIARY':
1375           case 'MUST':
1376           case 'MAY':
1377                     if ($name != ""){
1378                       $objectclasses[$ocname][$name]= $this->value2container($value);
1379                     }
1380                     $name= $chunk;
1381                     $value= "";
1382                     break;
1384           default:  $value.= $chunk." ";
1385         }
1386       }
1388     }
1390     return $objectclasses;
1391   }
1393   function value2container($value)
1394   {
1395     /* Set emtpy values to "true" only */
1396     if (preg_match('/^\s*$/', $value)){
1397       return true;
1398     }
1400     /* Remove ' and " if needed */
1401     $value= preg_replace('/^[\'"]/', '', $value);
1402     $value= preg_replace('/[\'"] *$/', '', $value);
1404     /* Convert to array if $ is inside... */
1405     if (preg_match('/\$/', $value)){
1406       $container= preg_split('/\s*\$\s*/', $value);
1407     } else {
1408       $container= chop($value);
1409     }
1411     return ($container);
1412   }
1414   function log($string)
1415   {
1416     if (isset($_SESSION['config'])){
1417       $cfg= $_SESSION['config'];
1418       if (isset($cfg->current['LDAPSTATS']) && preg_match('/true/i', $cfg->current['LDAPSTATS'])){
1419         syslog (LOG_INFO, $string);
1420       }
1421     }
1422   }
1423   
1424   /* added by Guido Serra aka Zeph <zeph@purotesto.it> */
1425   function getCn($dn){
1426     $simple= split(",", $dn);
1428     foreach($simple as $piece) {
1429       $partial= split("=", $piece);
1431       if($partial[0] == "cn"){
1432         return $partial[1];
1433       }
1434     }
1436   }
1438   function get_naming_contexts($server, $admin= "", $password= "")
1439   {
1440     /* Build LDAP connection */
1441     $ds= ldap_connect ($server);
1442     if (!$ds) {
1443       die ("Can't bind to LDAP. No check possible!");
1444     }
1445     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
1446     $r= ldap_bind ($ds, $admin, $password);
1448     /* Get base to look for naming contexts */
1449     $sr  = @ldap_read ($ds, "", "objectClass=*", array("+"));
1450     $attr= @ldap_get_entries($ds,$sr);
1452     return ($attr[0]['namingcontexts']);
1453   }
1457 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1458 ?>