Code

Apply patch for #5210
[gosa.git] / trunk / gosa-plugins / fai / admin / fai / class_FAI.inc
1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9   /* TEST PHASE .... */
11   static function get_all_objects_for_given_object($dn,$filter,$detailed = false)
12   {
13     $res  = FAI::get_all_objects_for_given_base($dn,$filter,$detailed);
14     $name = preg_replace("/,ou=.*$/","",$dn);
15     $entries = array();
16     foreach($res as $entry_dn => $data){
17       if(!preg_match("/,".$name.",/",$entry_dn)) continue;
18       $entries[$entry_dn] = $data; 
19     }
20     return($entries);
21   }
26   /* Returns all object for the given release.
27      This function resolves the releases  
28      from base up to the given dn.
29    */
30   static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
31   {
32     global $config;
33     $ldap = $config->get_ldap_link();
34     $ldap->cd($config->current['BASE']);
35     $res = array();
36     $tmp = array();
38     if(!FAI::is_release_department($Current_DN)) {
39 #      return($res);
40     }
42     /* Collect some basic informations and initialize some variables */ 
43     $base_release       = FAI::get_release_dn($Current_DN);
44     $previous_releases  = array_reverse(FAI::get_previous_releases_of_this_release($base_release,true));
46     $ldap->cat($base_release);
47     $attrs = $ldap->fetch();
48     $FAIstate = "branch";
49     if(isset($attrs['FAIstate'][0])){
50       $FAIstate = $attrs['FAIstate'][0];
51     }
53     /* We must also include the given release dn */
54     $previous_releases[] = $base_release;
56     /* Walk through all releases */
57     foreach($previous_releases as $release){
59       /* Get fai departments */
60       $deps_to_search = FAI::get_FAI_departments($release); 
62       /* For every single department  (ou=hoos,ou ..) */
63       foreach($deps_to_search as $fai_base){
65         /* Ldap search for fai classes specified in this release */
66         $attributes  = array("dn","objectClass","FAIstate","cn");
67         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
69         /* check the returned objects, and add/replace them in our return variable */
70         foreach($res_tmp as $attr){
72           $buffer = array();
73           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
75           if(isset($attr['FAIstate'][0])){
76             if(preg_match("/removed/",$attr['FAIstate'][0])){
77               if(isset($res[$name])){
78                 unset($res[$name]);
79               }
80               continue;
81             }
82           }
84           /* Seems to be an inherited class, apply current FAIstate to this classes 
85            */
86           if(!preg_match("/".preg_quote($base_release, '/')."$/i",$attr['dn'])){
87             $buffer['FAIstate'] = $FAIstate; 
88           }else{
90             /* Seems to be created within this release department.
91                This indicates - it can't be of state "freeze"
92              */             
93             if(isset($attr['FAIstate'])){
94               $buffer['FAIstate'] = $attr['FAIstate'][0];
95             }else{
96               $buffer['FAIstate'] = "branch"; 
97             }
98           }
100           /* In detailed mode are some additonal informations visible */
101           if($detailed){
103             /* Create list of parents */
104             if(isset($res[$name])){
105               $buffer = $res[$name];
106               $buffer['parents'][] = $res[$name]['dn'];
107             }else{
108               $buffer['parents'] = array();
109             }
111             /* Append objectClass to resulsts */
112             foreach($attributes as $val){
113               if(isset($attr[$val])){
114                 $buffer[$val] = $attr[$val];
115               }
116             }
117             unset($buffer['objectClass']['count']);
118           }
120           /* Add this object to our list */
121           $buffer['dn']           = $attr['dn'];
122           $res[$name] = $buffer;
123         }
124       }
125     }
126     return($res);
127   }
130   /* Return all relevant FAI departments */
131   static function get_FAI_departments($suffix = "")
132   {
133     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
134     $tmp = array();
135     if(preg_match("/^,/",$suffix)){
136       $suffix = preg_replace("/^,/","",$suffix);
137     }
138     foreach($arr as $name){
139       if(empty($suffix)){
140         $tmp[$name] = "ou=".$name;
141       }else{
142         $tmp[$name] = "ou=".$name.",".$suffix;
143       }
144     }
145     return($tmp);
146   }
149   /* Return all releases within the given base */
150   static function get_all_releases_from_base($dn,$appendedName=false)
151   {
152     global $config;
154     if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
155       $base = get_ou('faiBaseRDN').$dn;
156     }else{
157       $base = $dn;
158     }
159     $res = array();  
161     $ldap = $config->get_ldap_link();
162     $ldap->cd($base);
163     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
164     while($attrs = $ldap->fetch()){
165       if($appendedName){
166         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
167       }else{
168         $res[$attrs['dn']] = $attrs['ou'][0];
169       }
170     }
171     return($res);
172   }
175   /* Add this object to list of objects, that must be checked for release saving */
176   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
177   {
178     /* Get ldap object */  
179     global $config;
180     $addObj['Current_DN'] = $Current_DN;
181     $addObj['objectAttrs']= $objectAttrs;
182     $addObj['removed']    = $removed;
183     $addObj['diff']       = TRUE;
185     if(!$removed){
186       $ldap = $config->get_ldap_link();
187       $ldap->cd($config->current['BASE']);
188       $parent_dn = FAI::get_parent_object($Current_DN);
190       /* Get some basic informations */
191       $parent_obj   = FAI::get_parent_release_object($Current_DN);
192       /* Check whether parent object is removed, do not create object in this case */
193       if(!empty($parent_obj) && !FAI::parent_is_removed($Current_DN)){
194         $ldap->cat($parent_obj,array("*"));
195         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
197         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
198           $addObj['diff'] = FALSE;
199         }
200       } 
201     }else{
203       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
204           we have to remove this name from all profiles in this release.
205       */
206       $ldap = $config->get_ldap_link();
207       $ldap->cd($config->current['BASE']);
208       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
210       /* Dont't try to modify non FAIclasses  
211        */
212       if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
213         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
214         echo "<br>-->".$Current_DN."<br>";
215         echo "<br>-->".$obj_dn."<br>";
216       }else{
218         /* Get source object and check if it is a base FAIclass
219          */
220         $ldap->cat($obj_dn);
221         $attrs = $ldap->fetch();
222         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
223         if(count(array_intersect($classes,$attrs['objectClass']))){
224           $cn    = $attrs['cn'][0];
226           /* Check if this is the last with this name in the current release.
227               In this case we have to remove the package name 
228               from all profiles in this release.
229            */
230           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
231               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
233           /* Check if this is the last class with this name.
234            */
235           if(count($classes) == 1){
237             /* Get all FAI Profiles 
238              */
239             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
240                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
242             /* Walk though all profiles and remove the source class name
243              */
244             foreach($profiles as $dn){
245               $ldap->cat($dn['dn']);
246               $attrs = $ldap->fetch();
248               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
250               /* Check if this Profile uses the source class ($cn)
251                */
252               $classlist = split(" ", $attrs['FAIclass']);
253               $new_classlist = "";
254               foreach($classlist as $class){
255                 if($class != $cn){
256                   $new_classlist = $new_classlist." ".$class;
257                 }
258               } 
259               $attrs['FAIclass'] = $new_classlist;
260               if(empty($attrs['FAIclass'])){
261                 $attrs['FAIclass'] = array();
262               }
263               $ldap->cd($dn['dn']);
264               $ldap->modify($attrs);
265               
266               if (!$ldap->success()){
267                 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
268               }
269             }
270           }
271         }
272       }
273     }
277     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
278     $FAI_objects_to_save[$Current_DN] =  $addObj;
279     session::set('FAI_objects_to_save',$FAI_objects_to_save);
280   }
283   /* Detect differences in attribute arrays  */
284   static function array_diff_FAI($ar1,$ar2)
285   {
287     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
288       $ar1['description'] = "";
289     }
290     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
291       $ar2['description'] = "";
292     }
294     if(count($ar1) != count($ar2)) {
295       return (true);
296     }
298     foreach($ar1 as $key1 => $val1){
300       if((is_array($val1)) && (count($val1)==1)){
301         $ar1[$key1] = $val1[0];
302       }
304       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
305         $val1 = $val1[0];
306         $ar2[$key1] = $ar2[$key1][0];
307       }
308     }
309     ksort($ar1);
310     ksort($ar2);
311     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
312       return(true);
313     }else{
314       return(false);
315     }
316   }
319   static function arr_diff($ar1,$ar2)
320   {
321     foreach($ar1 as $ak1 => $av1){
322       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
323         return(TRUE);    
324       }elseif(is_array($av1)){
325         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
326         if($ret) {
327           return(TRUE);
328         }
329       }
330     }
331     return(FALSE);
332   }
337   /* check which objects must be saved, and save them */
338   static function save_release_changes_now()
339   {
340     global $config;
341     /* Variable init*/
342     $to_save = array();
343     
344     $reload_fai_classes = FALSE;
346     /* check which objects must be saved */
347     if(!session::is_set('FAI_objects_to_save')){
348       return;
349     }
350     $FAI_objects_to_save = session::get('FAI_objects_to_save');
351     if(!is_array($FAI_objects_to_save)) {
352       print_a(array(session::get('FAI_objects_to_save')));
353       trigger_error("Can't save FAI objects, no array given.");
354       return;
355     }
356   
357     foreach($FAI_objects_to_save as $Current_DN => $object){
358       if($object['diff']){
359         $sub_name = $Current_DN;
360         while(isset($FAI_objects_to_save[$sub_name])){
361           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
362           unset($FAI_objects_to_save[$sub_name]);
363           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
364         }
365       }
366     }
367     session::set('FAI_objects_to_save',$FAI_objects_to_save);
369     /* Sort list of objects that must be saved, and ensure that 
370        container   objects are safed, before their childs are saved */
371     ksort($to_save);
372     $tmp = array();
373     foreach($to_save as $SubObjects){
374       foreach($SubObjects as $object){
375         $tmp[] = $object;
376       }
377     }
378     $to_save = $tmp;
381     /* Save objects and manage the correct release behavior*/
382     foreach($to_save as $save){
384       $Current_DN = $save['Current_DN'];
385       $removed    = $save['removed'];
386       $objectAttrs= $save['objectAttrs'];
388       /* Get ldap object */ 
389       $ldap = $config->get_ldap_link();
390       $ldap->cd($config->current['BASE']);
392       /* Get some basic informations */
393       $base_release       = FAI::get_release_dn($Current_DN);
394       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
395       $parent_obj         = FAI::get_parent_release_object($Current_DN);
396       $following_releases = $sub_releases;
398       /* Check if given dn exists or if is a new entry */
399       $ldap->cat($Current_DN);
400       if(!$ldap->count()){
401         $is_new = true;
402       }else{
403         $is_new = false;
404       }
406       /* if parameter removed is true, we have to add FAIstate to the current attrs 
407          FAIstate should end with ...|removed after this operation */  
408       if($removed ){
409         $ldap->cat($Current_DN);
411         /* Get current object, because we must add the FAIstate ...|removed */
412         if((!$ldap->count()) && !empty($parent_obj)){
413           $ldap->cat($parent_obj);
414         }
416         /* Check if we have found a suiteable object */ 
417         if(!$ldap->count()){
418           echo "Error can't remove this object ".$Current_DN;
419           return;
420         }else{
422           /* Set FAIstate to current objectAttrs */
423           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
424           if(isset($objectAttrs['FAIstate'][0])){
425             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
426               $objectAttrs['FAIstate'][0] .= "|removed";
427             }
428           }else{
429             $objectAttrs['FAIstate'][0] = "|removed";
430           }
432           /* Force reload of FAI classes */
433           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
434           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
435             $reload_fai_classes = TRUE;
436           }
437         }
438       }
440       /* Check if this a leaf release or not */ 
441       if(count($following_releases) == 0 ){
443         /* This is a leaf object. It isn't inherited by any other object */    
444         if(DEBUG_FAI_FUNC) { 
445           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
446           print_a($objectAttrs);
447         }
448         FAI::save_FAI_object($Current_DN,$objectAttrs);
450         /* Force reload of FAI classes */
451         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
452         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
453           $reload_fai_classes = TRUE;
454         }
456       }else{
458         /* This object is inherited by some sub releases */  
460         /* Get all releases, that inherit this object */ 
461         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
463         /* Get parent object */
464         $ldap->cat($parent_obj);
465         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
467         /* New objects require special handling */
468         if($is_new){
470           /* Force reload of FAI classes */
471           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
472           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
473             $reload_fai_classes = TRUE;
474           }
476           /* check if there is already an entry named like this,
477              in one of our parent releases */
478           if(!empty($parent_obj)){
479             if(DEBUG_FAI_FUNC) { 
480               echo "There is already an entry named like this.</b><br>";
482               echo "<b>Saving main object</b>".$Current_DN;
483               print_a($objectAttrs);
484             }    
485             FAI::save_FAI_object($Current_DN,$objectAttrs);
487             foreach($r as $key){
488               if(DEBUG_FAI_FUNC) { 
489                 echo "<b>Saving parent to following release</b> ".$key;
490                 print_a($parent_attrs);
491               }
492               FAI::save_FAI_object($key,$parent_attrs);
493             }
494           }else{
496             if(DEBUG_FAI_FUNC) { 
497               echo "<b>Saving main object</b>".$Current_DN;
498               print_a($objectAttrs);
499             }
500             FAI::save_FAI_object($Current_DN,$objectAttrs);
502             if(isset($objectAttrs['FAIstate'])){
503               $objectAttrs['FAIstate'] .= "|removed"; 
504             }else{
505               $objectAttrs['FAIstate'] = "|removed";
506             }
508             foreach($r as $key ){
509               /* Only save removed parent objects, not their children, unless
510                  they are a child of a copy-on-write parent in a subrelease */
511               if (FAI::is_parent_object($Current_DN) || FAI::is_child_of_cow_parent($key)){
512                 if(DEBUG_FAI_FUNC) { 
513                   echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
514                   print_a($objectAttrs);
515                 }
516                 FAI::save_FAI_object($key,$objectAttrs);
517               }
518             }
519           }
520         }else{
522           /* check if we must patch the follwing release */
523           if(!empty($r)){
525             foreach($r as $key ){
526               /* Append FAIstate tag to ensure that freezed objects stay freezed
527                */ 
528               $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
529               $parent_attrs['FAIstate'] = $rTag;
530               /* Don't copy over subobjects in subreleases if their parent is in "removed" state */
531               if(!FAI::parent_is_removed($key)){
532                 /* FAItemplateFile can be binary, therefore it needs to be fetched with
533                  * $ldap->get_attribute */
534                 if (isset($parent_attrs['FAItemplateFile'])) {
535                   $parent_attrs['FAItemplateFile'] = $ldap->get_attribute($parent_obj, 'FAItemplateFile');
536                 }
537                 if(DEBUG_FAI_FUNC) { 
538                   echo "<b>Copy current objects original attributes to next release</b> ".$key;
539                   print_a($parent_attrs);
540                 }
541                 FAI::save_FAI_object($key,$parent_attrs);
542               }
543             }
544           }
546           if(DEBUG_FAI_FUNC) { 
547             echo "<b>Saving current object</b>".$parent_obj;
548             print_a($objectAttrs);
549           }
550           FAI::save_FAI_object($parent_obj,$objectAttrs);
552           if(($parent_obj != $Current_DN)){
553             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
554           }
555         }
556       }
557     }
559     /* Reload GOsa si FAI DB/cache
560      */
561     if($reload_fai_classes){
562       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
563         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
564         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
565           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
566           $tmp = new $evt['CLASS_NAME']($config);
567           $tmp->set_type(TRIGGERED_EVENT);
568           $tmp->add_targets(array("GOSA"));
569           $o_queue = new gosaSupportDaemon();
570           if(!$o_queue->append($tmp)){
571             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
572           }
573         }
574       }
575     }
577     session::set('FAI_objects_to_save',array());
578   }
581   /* this function will remove all unused (deleted) objects,
582      that have no parent object. If $recursive is set to true,
583      also check sub releases. */
584   static function clean_up_releases($Current_DN, $recursive=true)
585   {
586     global $config;
587     $ldap = $config->get_ldap_link();
588     $ldap->cd($config->current['BASE']);
590     /* Collect some basic informations and initialize some variables */ 
591     $base_release       = FAI::get_release_dn($Current_DN);
592     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
593     $sub_releases       = array_keys(FAI::get_sub_releases_of_this_release($base_release,false));
594     $Kill = array();
595     $Skip = array();
597     /* We must also include the given release dn */
598     $previous_releases[] = $base_release;
600     $all_releases = $previous_releases;
602     if ($recursive) {
603       /* Merge parent, current and child releases into one big release to 
604          iterate over */
605       foreach($sub_releases as $sub_release){
606         $all_releases[] = $sub_release;
607       }
608     }
610     /* Walk through all releases */
611     foreach($all_releases as $release){
613       /* Get fai departments */
614       $deps_to_search = FAI::get_FAI_departments($release); 
616       /* For every single department  (ou=hoos,ou ..) */
617       foreach($deps_to_search as $fai_base){
619         /* Ldap search for fai classes specified in this release */
620         $ldap->cd($fai_base);
621         $ldap->search("(|(objectClass=FAIclass)(objectClass=FAIdebconfInfo))",array("dn","objectClass","FAIstate"));
623         /* check the returned objects, and add/replace them in our return variable */
624         while($attr = $ldap->fetch()){
626           $buffer = array();
627 #        $name = str_ireplace($release,"",$attr['dn']);
628           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
630           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
632             /* Check if this object is required somehow */    
633             if(!isset($Skip[$name])){
634               $Kill[$attr['dn']] = $attr['dn'];
635             }
636           }else{
638             /* This object is required (not removed), so do not 
639                delete any following sub releases of this object */
640             $Skip[$name] = $attr['dn'];
641           }
642         }
643       }
644     }
645     return($Kill);
646   }
649   /* Remove numeric index and 'count' from ldap->fetch result */
650   static function prepare_ldap_fetch_to_be_saved($attrs)
651   {
652     foreach($attrs as $key => $value){
653       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
654         unset($attrs[$key]);
655       }
656       if(is_array($value) && isset($value['count'])){
657         unset($attrs[$key]['count']);
658       }
659     }
660     return($attrs);
661   }
664   /* Save given attrs to specified dn*/
665   static function save_FAI_object($dn,$attrs)
666   {
667     global $config;
668     $ldap = $config->get_ldap_link();
669     $ldap->cd($config->current['BASE']);
670     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
671     $ldap->cd($dn);
673     $ui= get_userinfo();
674     FAI::tag_attrs($attrs, $dn, $ui->gosaUnitTag);
676     $ldap->cat($dn,array("dn"));
677     if($ldap->count()){
679       /* Remove FAIstate*/
680       if(!isset($attrs['FAIstate'])){
681         $attrs['FAIstate'] = array();
682       }
684       $ldap->modify($attrs);
685     }else{
687       /* Unset description if empty  */
688       if(empty($attrs['description'])){
689         unset($attrs['description']);
690       }    
692       $ldap->add($attrs);
693     }
694     if (!$ldap->success()){
695       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
696     }
697   }
700   /* Return FAIstate freeze branch or "" for specified release department */
701   static function get_release_tag($dn)
702   {
703     global $config;
704     $ldap = $config->get_ldap_link();
705     $ldap->cd($dn);
706     $ldap->cat($dn,array("FAIstate"));
708     if($ldap->count()){
710       $attr = $ldap->fetch();
711       if(isset($attr['FAIstate'][0])){
712         if(preg_match("/freeze/",$attr['FAIstate'][0])){
713           return("freeze");
714         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
715           return("branch");
716         }
717       }
718     }
719     return("");
720   }
723   static function get_following_releases_that_inherit_this_object($dn)
724   {
725     global $config;
726     $ldap = $config->get_ldap_link();
727     $ldap->cd($config->current['BASE']);
729     $ret = array();
731     /* Get base release */
732     $base_release = FAI::get_release_dn($dn);
734     /* Get previous release dns */
735     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
737     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
738 #  $dn_suffix = str_ireplace($base_release,"",$dn);
739     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
741     /* Check if given object also exists whitin one of these releases */
742     foreach($sub_releases as $p_release => $name){
744       $check_dn = $dn_suffix.$p_release;
746       $ldap->cat($check_dn,array("dn","objectClass"));
748       if($ldap->count()){
749         //return($ret);
750       }else{
751         $ret[$check_dn]=$check_dn;
752       }
753     }
754     return($ret);
755   }
758   /* Get previous version of the object dn */
759   static function get_parent_release_object($dn,$include_myself=true)
760   {
761     global $config;
762     $ldap = $config->get_ldap_link();
763     $ldap->cd($config->current['BASE']);
764     $previous_releases= array();
766     /* Get base release */
767     $base_release = FAI::get_release_dn($dn);
768     if($include_myself){
769       $previous_releases[] = $base_release;  
770     }
772     /* Get previous release dns */
773     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
774     foreach($tmp as $release){
775       $previous_releases[] = $release;
776     }
778     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
779 #  $dn_suffix = str_ireplace($base_release,"",$dn);
780     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
782     /* Check if given object also exists whitin one of these releases */
783     foreach($previous_releases as $p_release){
784       $check_dn = $dn_suffix.$p_release;
785       $ldap->cat($check_dn,array("dn","objectClass"));
787       if($ldap->count()){
788         return($check_dn);
789       }
790     }
791     return("");
792   }
795   /* return release names of all parent releases */
796   static function get_previous_releases_of_this_release($dn,$flat)
797   {
798     global $config;
799     $ldap = $config->get_ldap_link();
800     $ldap->cd($config->current['BASE']);
801     $ret = array();
803     /* Explode dns into pieces, to be able to build parent dns */
804     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
806     if(!is_array($dns_to_check)){
807       return;  
808     }
810     /* Unset first entry which represents the given dn */
811     unset($dns_to_check['count']); 
812     unset($dns_to_check[key($dns_to_check)]);
814     /* Create dns addresses and check if this dn is a release dn */
815     $id = 0;
816     while(count($dns_to_check)){
818       /* build parent dn */
819       $new_dn = "";
820       foreach($dns_to_check as $part){
821         $new_dn .= $part.",";
822       }
823       $new_dn .= $config->current['BASE'];
825       /* check if this dn is a release */
826       if(FAI::is_release_department($new_dn)){
827         if($flat){
828           $ret[$id] = $new_dn; 
829         }else{
830           $ret = array($new_dn=>$ret); 
831         }
832         $id ++;
833       }else{
834         return($ret);
835       }
836       reset($dns_to_check);
837       unset($dns_to_check[key($dns_to_check)]);
838     }
839     return($ret);
840   } 
843   /* This function returns all sub release names, recursivly  */
844   static function get_sub_releases_of_this_release($dn,$flat = false)
845   {
846     global $config;
847     $res  = array();
848     $ldap = $config->get_ldap_link();
849     $ldap->cd($config->current['BASE']);
850     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
851     while($attr = $ldap->fetch()){
853       /* Append department name */
854       if($flat){
855         $res[$attr['dn']] = $attr['ou'][0];
856       }else{
857         $res[$attr['dn']] = array();
858       }
860       /* Get sub release departments of this department */
861       if(in_array("FAIbranch",$attr['objectClass'])) {
862         if($flat){
863           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
864           foreach($tmp as $dn => $value){
865             $res[$dn]=$value;
866           }
867         }else{
868           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
869         }
870       }
871     }
872     return($res);
873   }
876   /* Check if the given department is a release department */
877   static function is_release_department($dn)
878   {
879     global $config;
880     $ldap = $config->get_ldap_link();
881     $ldap->cd($config->current['BASE']);
882     $ldap->cat($dn,array("objectClass","ou"));
884     /* Check objectClasses and name to check if this is a release department */
885     if($ldap->count()){
886       $attrs = $ldap->fetch();
888       $ou = "";
889       if(isset($attrs['ou'][0])){
890         $ou = $attrs['ou'][0];  
891       }
893       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
894         return($attrs['dn']);
895       }
896     }
897     return(false);
898   }
901   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
902   {
903     global $config;
904     $start = microtime(TRUE);
905     $source_release = trim($source_release,"/");
907     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
909     $sub_releases = array();
910     $source_dn = "";
911     
912     $tmp = split("\/",$source_release);
913     foreach($tmp as $part){
914       if(empty($part)){
915         continue;
916       }
917       $source_dn            = "ou=".$part.",".$source_dn;
918       $sub_releases[$part]  = $source_dn;
919     }
921     /* Get all groups */
922     $ldap =$config->get_ldap_link();
923     $ldap->cd($config->current['BASE']);
924     $ldap->search("(objectClass=posixGroup)",array("dn"));
925     $groups = array();
926     while($attrs = $ldap->fetch()){
927       $groups[$attrs['dn']] = $attrs;
928     }
930     /* Get all FAI releases, to be able to create missing group application releases 
931         with the correct type of release (FAIstate=freeze/branch).
932      */
933     $f_releases = array();
934     $ldap->cd ($config->current['BASE']);
935     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
936     while($attrs = $ldap->fetch()){
937       foreach($sub_releases as $sub_rel){
938         if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
939           $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
940         }
941       }
942     }
944     /* Get all group releases */
945     $g_releases = array();
946     foreach($groups as $dn => $data){
947       $ldap->cd($dn);
948       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
949       while($attrs = $ldap->fetch()){
950         $g_releases[$attrs['dn']] = $attrs;
951       }
952     }
954     /* Check if base releases exists.
955        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
956      */
957     foreach($sub_releases as $name => $sub_rel){
959       $FAIstate = "";
960       if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
961         $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
962       }
964       foreach($groups as $dn => $data){
965         if(!isset($g_releases[$sub_rel.$dn])){
966           $ldap->cd($dn);
967           $r_data = array();
968           $r_data['ou'] = $name;
969           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
970           if(!empty($FAIstate)) {
971             $r_data['FAIstate'] = $FAIstate;
972           }
973  
974           $ldap->cd($sub_rel.$dn) ;
975           $ldap->add($r_data);
976           echo "&nbsp;<b>"._("Object").":</b> ";
977           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
978           flush();
979         }
980       }
981     } 
982  
983     /* Create new release container in each group.
984      */
985     $n_data = array();
986     $n_data = array();
987     $n_data['ou'] = $destination_name;
988     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
989     if(!empty($type)){
990       $n_data['FAIstate'] = $type."/cow";
991     }
993     foreach($groups as $dn => $att){
994       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
995       if(!isset($g_releases[$n_dn])){
996         $ldap->cd ($n_dn);
997         $ldap->add($n_data);
998         echo "&nbsp;<b>"._("Object").":</b> ";
999         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
1000         flush();
1001       }
1002     }
1004     /* If the source release is empty, then create a new release by copying 
1005         all group application menus into a new ou=$destination_name release container.
1006       
1007        If the source release is not empty. 
1008          We detect all releases which match the source release dn and copy the contents.
1009      */
1010     if(empty($source_release)){
1011       $source_dns = $groups;
1012     }else{
1013       $source_dns = array();
1014       foreach($g_releases as $dn => $data){
1015         if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1016           $source_dns[$dn] = $data; 
1017         }
1018       }
1019     }
1021     /* Detect all menu object we have to copy 
1022      */
1023     $to_copy = array();
1024     foreach($source_dns as $dn => $attrs){
1025       $ldap->cd($dn);
1026       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1027       while($attrs = $ldap->fetch()){
1028         $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1029         $to_copy[$attrs['dn']] = $destination;
1030       }
1031     }
1032    
1033     /* At least create the menu objects object */
1034     $plug = new plugin($config);
1035     foreach($to_copy as $source => $destination){
1036       $ldap->cat($destination);
1037       if($ldap->count()){
1038         echo "&nbsp;<b>"._("Object").":</b> ";
1039         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1040         flush();
1041       }else{
1042         $plug->copy($source,$destination);
1043         echo "&nbsp;<b>"._("Object").":</b> ";
1044         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1045         flush();
1046       }
1047     }
1048   }
1051   /*! \brief Create a new FAI branch.
1052    *  @param $sourcedn          String  The source release dn
1053    *  @param $destinationdn     String  The destination dn
1054    *  @param $destinationName   String  The name of the new release
1055    *  @param $type              String  The release type (freeze/branch)
1056    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1057    *  @param $depth             Integer Current depth of recursion.
1058    */
1059   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1060   {
1061     global $config;
1062     error_reporting(E_ALL | E_STRICT);
1063     $ldap     = $config->get_ldap_link();
1064     $basedn   = $config->current['BASE'];
1065     $delarray = array();
1067     /* The following code will output a status string
1068      *  for each handled object, in a seperate iframe.
1069      */
1072     /* Display current action information.
1073      */
1074     if($is_first){
1075       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1076     }else{
1077       if(preg_match("/^ou=/",$sourcedn)){
1078         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1079       }else{
1080         $tmp = split(",",$sourcedn);
1081         echo "&nbsp;<b>"._("Object").":</b> ";
1082         $deststr = LDAP::fix($destinationdn);
1083         if(strlen($deststr) > 96){
1084           $deststr = substr($deststr,0,96)."...";
1085         }
1086         echo $deststr."<br>";
1087       }
1088     }
1089     /* .. immediately display infos */
1090     flush();
1092     /* Check if destination entry already exists
1093      */
1094     $ldap->cat($destinationdn);
1095     if($ldap->count()){
1096       echo _("Could not create new release, the destination dn is already in use.");
1097       return;
1098     }else{
1100       $ldap->clearResult();
1102       /* Get source entry
1103        *  if it does not exist, abort here.
1104        */
1105       $ldap->cd($basedn);
1106       $ldap->cat($sourcedn);
1107       $attr = $ldap->fetch();
1108       if((!$attr) || (count($attr)) ==0) {
1109         echo _("Error while fetching source dn - aborted!");
1110         return;
1111       }
1113       /* The current object we want to create is an department.
1114        * Create the department and add the FAIbranch tag.
1115        */
1116       if(in_array("organizationalUnit",$attr['objectClass'])){
1117         $attr['dn'] = LDAP::convert($destinationdn);
1118         $ldap->cd($basedn);
1119         $ldap->create_missing_trees($destinationdn);
1120         $ldap->cd($destinationdn);
1122         /* If is first entry, append FAIbranch to department entry */
1123         if($is_first){
1124           $ldap->cat($destinationdn);
1125           $attr= $ldap->fetch();
1126           /* Filter unneeded informations */
1127           foreach($attr as $key => $value){
1128             if(is_numeric($key)) unset($attr[$key]);
1129             if(isset($attr[$key]['count'])){
1130               if(is_array($attr[$key])){
1131                 unset($attr[$key]['count']);
1132               }
1133             }
1134           }
1136           unset($attr['count']);
1137           unset($attr['dn']);
1139           /* Add marking attribute */
1140           $attr['objectClass'][] = "FAIbranch";
1141           $attr['FAIstate'] = $type;
1143           /* Add this entry */
1144           $ldap->modify($attr);
1145         }
1146       }else{
1148         /* Replicate all relevant FAI objects here.
1149          * FAI objects, Apps and Mimetypes.
1150          * Get all attributes as binary value, to ensure that Icon, File template aso
1151          *  are created correctly.
1152          */
1153         foreach($attr as $key => $value){
1155           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1156             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1157             $ei= ldap_first_entry($ldap->cid, $sr);
1158             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1159               $attr[$key] = $tmp;
1160             }
1161           }
1163           if(is_numeric($key)) unset($attr[$key]);
1164           if(isset($attr[$key]['count'])){
1165             if(is_array($attr[$key])){
1166               unset($attr[$key]['count']);
1167             }
1168           }
1169         }
1170         unset($attr['count']);
1171         unset($attr['dn']);
1172         if(!in_array("FAIobject",$attr['objectClass'])){
1173           $attr['objectClass'][] = "FAIobject";
1174         }
1175         $attr['FAIstate'] = $type;
1177         /* Add entry
1178          */
1179         $ldap->cd($destinationdn);
1180         $ldap->cat($destinationdn);
1182         $a = $ldap->fetch();
1183         if(!count($a)){
1184           $ldap->add($attr);
1185         }
1187         if(!$ldap->success()){
1189           /* Some error occurred */
1190           msg_dialog::display(_("Fatal error"),
1191               sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1192                 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1193           exit();
1194         }
1195       }
1196     }
1198     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1200     /* Prepare for recursive copy.
1201      * Get all object within the source dn and
1202      *  call the recursive copy for each.
1203      */
1204     $ldap->ls ("(objectClass=*)",$sourcedn);
1205     while ($ldap->fetch()){
1206       $deldn= $ldap->getDN();
1207       $delarray[$deldn]= strlen($deldn);
1208     }
1209     asort ($delarray);
1210     reset ($delarray);
1211     $depth ++;
1212     foreach($delarray as $dn => $bla){
1213       if($dn != $destinationdn){
1214         $ldap->cd($basedn);
1215         $item = $ldap->fetch($ldap->cat($dn));
1216         if(!in_array("FAIbranch",$item['objectClass'])){
1217           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1218         }
1219       }
1220     }
1221     if($is_first){
1222       echo "<p class='seperator'>&nbsp;</p>";
1223     }
1224   }
1228   /* This function returns the dn of the object release */
1229   static function get_release_dn($Current_DN)
1230   {
1231     global $config;
1232     $ldap = $config->get_ldap_link();
1233     $ldap->cd($config->current['BASE']);
1235     /* Split dn into pices */ 
1236     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1238     if(!is_array($dns_to_check)){
1239       return;  
1240     }
1242     /* Use dn pieces, to create sub dns like 
1243        ou=test,ou=1,ou=0...
1244        ou=1,ou=0...
1245        ou=0... 
1246        To check which dn is our release container.
1247      */
1248     unset($dns_to_check['count']); 
1249     while(count($dns_to_check)){
1251       /* Create dn */
1252       $new_dn = "";
1253       foreach($dns_to_check as $part){
1254         $new_dn .= $part.",";
1255       }
1256       $new_dn .= $config->current['BASE'];
1258       /* Check if this dn is a release dn */
1259       if(FAI::is_release_department($new_dn)){
1260         return($new_dn);
1261       }
1263       /* Remove first element of dn pieces */
1264       reset($dns_to_check);
1265       unset($dns_to_check[key($dns_to_check)]);
1266     }
1267     return("");
1268   }
1271   static function tag_attrs(&$at, $dn= "", $tag= "", $show= false)
1272   {                                                        
1273     /* Remove tags that may already be here... */                         
1274     remove_objectClass("gosaAdministrativeUnitTag", $at);                 
1275     if (isset($at['gosaUnitTag'])){                                       
1276         unset($at['gosaUnitTag']);                                        
1277     }                                                                     
1279     /* Set tag? */
1280     if ($tag != ""){
1281       add_objectClass("gosaAdministrativeUnitTag", $at);
1282       $at['gosaUnitTag']= $tag;                         
1283     }                                                   
1285     /* Initially this object was tagged. 
1286        - But now, it is no longer inside a tagged department. 
1287        So force the remove of the tag.                        
1288        (objectClass was already removed obove)                
1289      */                                                       
1290     if($tag == ""){                     
1291       $at['gosaUnitTag'] = array();                           
1292     }                                                         
1293   }                                                           
1295   /* Returns true if this is a parent object, e.g. FAIpartitionTable, not FAIpartitionDisk */
1296   static function is_parent_object($dn)
1297   {
1298     global $config;
1299     $Current_DN = $dn;
1301     /* special case partitions and debconf variables, as they don't start with cn= in their DN */
1302     if (preg_match('/^(FAIpartitionNr|FAIvariable)=/', $Current_DN)){
1303       return false;
1304     }
1306     $parent_dn = preg_replace('/^cn=[^,.]*,/', '', $Current_DN);
1307     if (preg_match('/^cn=/', $parent_dn)) {
1308       $ldap = $config->get_ldap_link();
1309       $ldap->cd($config->current['BASE']);
1310       $ldap->cat($parent_dn);
1311       if($ldap->count()){
1312         return false;
1313       }
1314     }else{
1315       return true;
1316     }
1317   }
1319   /* Return child objects, if there are any */
1320   static function get_child_objects($dn)
1321   {
1322     global $config;
1323     $Current_DN = $dn;
1324     $children= array();
1326     if (FAI::is_parent_object($Current_DN)){
1327       $ldap = $config->get_ldap_link();
1328       $ldap->cd($dn);
1329       $ldap->search("(objectClass=FAIclass)",array("dn"));
1330       while($attrs = $ldap->fetch()){
1331         if(preg_match("/".preg_quote($Current_DN, '/')."/",$attrs['dn']) && $attrs['dn'] != $Current_DN){
1332           $children[] = $attrs['dn'];
1333         }
1334       }
1335     }
1336     return $children;
1337   }
1339   /* Get the DN of the parent object; e.g. the FAIpartitionTable of a FAIpartitionDisk.
1340      If $check is false, do not check whether the parent actually exists in LDAP */
1341   static function get_parent_object($dn, $check=true)
1342   {
1343     global $config;
1344     $Current_DN = $dn;
1345     $i = 0;
1347     $tmp_dn = $Current_DN;
1348     $parent_dn = array();
1350     /* special case partitions and debconf variables, as they don't start with cn= in their DN */
1351     $tmp_dn = preg_replace('/^(FAIpartitionNr|FAIvariable)=/', 'cn=', $tmp_dn);
1353     $tmp_dn = gosa_ldap_explode_dn($tmp_dn);
1354     while(preg_match('/^cn=/', $tmp_dn[$i])) {
1355       $i++;
1356     }
1357     /* DN part does not start with cn= anymore, remove one from the counter to get the
1358        last CN element */
1359     $i--;
1361     for ($i;$i<$tmp_dn['count'];$i++) {
1362       $parent_dn[] = trim($tmp_dn[$i]);
1363     }
1364     $parent_dn = join($parent_dn, ',');
1366     if ($parent_dn != $Current_DN){
1367       if($check){
1368         $ldap = $config->get_ldap_link();
1369         $ldap->cd($config->current['BASE']);
1370         $ldap->cat($parent_dn);
1371         if(!$ldap->count()){
1372           return "";
1373         }
1374       }
1375       return $parent_dn;
1376     }
1377     return "";
1378   }
1380   /* Check whether parent object is removed */
1381   static function parent_is_removed($dn)
1382   {
1383     global $config;
1384     $Current_DN = $dn;
1386     $ldap = $config->get_ldap_link();
1387     $parent_dn = FAI::get_parent_object($Current_DN);
1388     if ($parent_dn) { 
1389       $ldap->cd($config->current['BASE']);
1390       $ldap->cat($parent_dn);
1391       $parentObjectAttrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
1392       if(isset($parentObjectAttrs['FAIstate'][0])){
1393         if(preg_match("/removed$/",$parentObjectAttrs['FAIstate'][0])){
1394           return true;
1395         }
1396       }
1397     } 
1398     return false;
1399   }
1401   /* Check whether this is a child object of a Copy-on-Write parent */
1402   static function is_child_of_cow_parent($dn)
1403   { 
1404     global $config;
1405     $Current_DN = $dn;
1406     $parent_dn = "";
1408     if (!FAI::is_parent_object($Current_DN)){
1410       /* This is a child object; check that the parent object is not 
1411          marked as removed */
1412       $cow_parent_dn = FAI::get_parent_object($Current_DN, false);
1413       if ($cow_parent_dn && !FAI::parent_is_removed($Current_DN)){
1415         /* This is a child object, check whether the parent object in 
1416            the main release exists */
1417         $main_parent_dn = FAI::get_parent_release_object($cow_parent_dn);
1418         $ldap = $config->get_ldap_link();
1419         $ldap->cd($config->current['BASE']);
1420         $ldap->cat($main_parent_dn);
1421         if($ldap->count()){
1422           return true;
1423         }
1424       }
1425     }
1426     return false;
1427   }
1429   static function get_leaf_objects($dn, $cn, $subclass, $rdn) {
1430     $valid_releases = FAI::get_previous_releases_of_this_release(FAI::get_release_dn($dn), true);
1431     /* Remove the last release DN */
1432     array_pop($valid_releases);
1433     $valid_releases[] = FAI::get_release_dn($dn);
1435     $objects = FAI::get_all_objects_for_given_base($dn,"(&(objectClass=FAIclass)(objectClass=".$subclass."))");
1436     $res = array();
1437     /* Strip elements which are not a leaf object of the current dn */
1438     foreach($objects as $obj){
1439       $keep = FALSE;
1440       foreach($valid_releases as $valid_release) {
1441         if (preg_match("/cn=".$cn.",".$rdn.$valid_release."$/", $obj['dn'])) {
1442           $keep = TRUE;
1443           break;
1444         }
1445       }
1447       if ($keep) {
1448         $res[] = $obj;
1449       }
1450     }
1452     return $res;
1453   }
1455     
1461 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1462 ?>