1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9 /* TEST PHASE .... */
11 /* Returns all object for the given release.
12 This function resolves the releases
13 from base up to the given dn.
14 */
15 static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
16 {
17 global $config;
18 $ldap = $config->get_ldap_link();
19 $ldap->cd($config->current['BASE']);
20 $res = array();
21 $tmp = array();
23 if(!FAI::is_release_department($Current_DN)) {
24 return($res);
25 }
27 /* Collect some basic informations and initialize some variables */
28 $base_release = FAI::get_release_dn($Current_DN);
29 $previous_releases = array_reverse(FAI::get_previous_releases_of_this_release($base_release,true));
31 $ldap->cat($base_release);
32 $attrs = $ldap->fetch();
33 $FAIstate = "branch";
34 if(isset($attrs['FAIstate'][0])){
35 $FAIstate = $attrs['FAIstate'][0];
36 }
38 /* We must also include the given release dn */
39 $previous_releases[] = $base_release;
41 /* Walk through all releases */
42 foreach($previous_releases as $release){
44 /* Get fai departments */
45 $deps_to_search = FAI::get_FAI_departments($release);
47 /* For every single department (ou=hoos,ou ..) */
48 foreach($deps_to_search as $fai_base){
50 /* Ldap search for fai classes specified in this release */
51 $attributes = array("dn","objectClass","FAIstate","cn");
52 $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
54 /* check the returned objects, and add/replace them in our return variable */
55 foreach($res_tmp as $attr){
57 $buffer = array();
58 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
60 if(isset($attr['FAIstate'][0])){
61 if(preg_match("/removed$/",$attr['FAIstate'][0])){
62 if(isset($res[$name])){
63 unset($res[$name]);
64 }
65 continue;
66 }
67 }
69 /* Seems to be an inherited class, apply current FAIstate to this classes
70 */
71 if(!preg_match("/".normalizePreg($base_release)."$/i",$attr['dn'])){
72 $buffer['FAIstate'] = $FAIstate;
73 }else{
75 /* Seems to be created within this release department.
76 This indicates - it can't be of state "freeze"
77 */
78 if(isset($attr['FAIstate'])){
79 $buffer['FAIstate'] = $attr['FAIstate'][0];
80 }else{
81 $buffer['FAIstate'] = "branch";
82 }
83 }
85 /* In detailed mode are some additonal informations visible */
86 if($detailed){
88 /* Create list of parents */
89 if(isset($res[$name])){
90 $buffer = $res[$name];
91 $buffer['parents'][] = $res[$name]['dn'];
92 }else{
93 $buffer['parents'] = array();
94 }
96 /* Append objectClass to resulsts */
97 foreach($attributes as $val){
98 if(isset($attr[$val])){
99 $buffer[$val] = $attr[$val];
100 }
101 }
102 unset($buffer['objectClass']['count']);
103 }
105 /* Add this object to our list */
106 $buffer['dn'] = $attr['dn'];
107 $res[$name] = $buffer;
108 }
109 }
110 }
111 return($res);
112 }
115 /* Return all relevant FAI departments */
116 static function get_FAI_departments($suffix = "")
117 {
118 $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
119 $tmp = array();
120 if(preg_match("/^,/",$suffix)){
121 $suffix = preg_replace("/^,/","",$suffix);
122 }
123 foreach($arr as $name){
124 if(empty($suffix)){
125 $tmp[$name] = "ou=".$name;
126 }else{
127 $tmp[$name] = "ou=".$name.",".$suffix;
128 }
129 }
130 return($tmp);
131 }
134 /* Return all releases within the given base */
135 static function get_all_releases_from_base($dn,$appendedName=false)
136 {
137 global $config;
139 if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
140 $base = get_ou('faiou').$dn;
141 }else{
142 $base = $dn;
143 }
144 $res = array();
146 $ldap = $config->get_ldap_link();
147 $ldap->cd($base);
148 $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
149 while($attrs = $ldap->fetch()){
150 if($appendedName){
151 $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
152 }else{
153 $res[$attrs['dn']] = $attrs['ou'][0];
154 }
155 }
156 return($res);
157 }
160 /* Add this object to list of objects, that must be checked for release saving */
161 static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
162 {
163 /* Get ldap object */
164 global $config;
165 $addObj['Current_DN'] = $Current_DN;
166 $addObj['objectAttrs']= $objectAttrs;
167 $addObj['removed'] = $removed;
168 $addObj['diff'] = TRUE;
170 if(!$removed){
171 $ldap = $config->get_ldap_link();
172 $ldap->cd($config->current['BASE']);
174 /* Get some basic informations */
175 $parent_obj = FAI::get_parent_release_object($Current_DN);
176 if(!empty($parent_obj)){
177 $ldap->cat($parent_obj,array("*"));
178 $attrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
180 if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
181 $addObj['diff'] = FALSE;
182 }
183 }
184 }else{
186 /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
187 we have to remove this name from all profiles in this release.
188 */
189 $ldap = $config->get_ldap_link();
190 $ldap->cd($config->current['BASE']);
191 $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
193 /* Dont't try to modify non FAIclasses
194 */
195 if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
196 trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);
197 echo "<br>-->".$Current_DN."<br>";
198 echo "<br>-->".$obj_dn."<br>";
199 }else{
201 /* Get source object and check if it is a base FAIclass
202 */
203 $ldap->cat($obj_dn);
204 $attrs = $ldap->fetch();
205 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
206 if(count(array_intersect($classes,$attrs['objectClass']))){
207 $cn = $attrs['cn'][0];
209 /* Check if this is the last with this name in the current release.
210 In this case we have to remove the package name
211 from all profiles in this release.
212 */
213 $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
214 "(&(objectClass=FAIclass)(cn=".$cn."))");
216 /* Check if this is the last class with this name.
217 */
218 if(count($classes) == 1){
220 /* Get all FAI Profiles
221 */
222 $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
223 "(&(objectClass=FAIprofile)(FAIclass=*))");
225 /* Walk though all profiles and remove the source class name
226 */
227 foreach($profiles as $dn){
228 $ldap->cat($dn['dn']);
229 $attrs = $ldap->fetch();
231 $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
233 /* Check if this Profile uses the source class ($cn)
234 */
235 if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
236 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
237 if(empty($attrs['FAIclass'])){
238 $attrs['FAIclass'] = array();
239 }
240 $ldap->cd($dn['dn']);
241 $ldap->modify($attrs);
243 if (!$ldap->success()){
244 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
245 }
246 }
247 }
248 }
249 }
250 }
251 }
255 $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
256 $FAI_objects_to_save[$Current_DN] = $addObj;
257 session::set('FAI_objects_to_save',$FAI_objects_to_save);
258 }
261 /* Detect differences in attribute arrays */
262 static function array_diff_FAI($ar1,$ar2)
263 {
265 if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
266 $ar1['description'] = "";
267 }
268 if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
269 $ar2['description'] = "";
270 }
272 if(count($ar1) != count($ar2)) {
273 return (true);
274 }
276 foreach($ar1 as $key1 => $val1){
278 if((is_array($val1)) && (count($val1)==1)){
279 $ar1[$key1] = $val1[0];
280 }
282 if(isset($ar2[$key1])&& (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
283 $val1 = $val1[0];
284 $ar2[$key1] = $ar2[$key1][0];
285 }
286 }
287 ksort($ar1);
288 ksort($ar2);
289 if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
290 return(true);
291 }else{
292 return(false);
293 }
294 }
297 static function arr_diff($ar1,$ar2)
298 {
299 foreach($ar1 as $ak1 => $av1){
300 if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
301 return(TRUE);
302 }elseif(is_array($av1)){
303 $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
304 if($ret) {
305 return(TRUE);
306 }
307 }
308 }
309 return(FALSE);
310 }
315 /* check which objects must be saved, and save them */
316 static function save_release_changes_now()
317 {
318 global $config;
319 /* Variable init*/
320 $to_save = array();
322 $reload_fai_classes = FALSE;
324 /* check which objects must be saved */
325 if(!session::is_set('FAI_objects_to_save')){
326 return;
327 }
328 $FAI_objects_to_save = session::get('FAI_objects_to_save');
329 if(!is_array($FAI_objects_to_save)) {
330 print_a(array(session::get('FAI_objects_to_save')));
331 trigger_error("Can't save FAI objects, no array given.");
332 return;
333 }
335 foreach($FAI_objects_to_save as $Current_DN => $object){
336 if($object['diff']){
337 $sub_name = $Current_DN;
338 while(isset($FAI_objects_to_save[$sub_name])){
339 $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name];
340 unset($FAI_objects_to_save[$sub_name]);
341 $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
342 }
343 }
344 }
345 session::set('FAI_objects_to_save',$FAI_objects_to_save);
347 /* Sort list of objects that must be saved, and ensure that
348 container objects are safed, before their childs are saved */
349 ksort($to_save);
350 $tmp = array();
351 foreach($to_save as $SubObjects){
352 foreach($SubObjects as $object){
353 $tmp[] = $object;
354 }
355 }
356 $to_save = $tmp;
359 /* Save objects and manage the correct release behavior*/
360 foreach($to_save as $save){
362 $Current_DN = $save['Current_DN'];
363 $removed = $save['removed'];
364 $objectAttrs= $save['objectAttrs'];
366 /* Get ldap object */
367 $ldap = $config->get_ldap_link();
368 $ldap->cd($config->current['BASE']);
370 /* Get some basic informations */
371 $base_release = FAI::get_release_dn($Current_DN);
372 $sub_releases = FAI::get_sub_releases_of_this_release($base_release,true);
373 $parent_obj = FAI::get_parent_release_object($Current_DN);
374 $following_releases = $sub_releases;
376 /* Check if given dn exists or if is a new entry */
377 $ldap->cat($Current_DN);
378 if(!$ldap->count()){
379 $is_new = true;
380 }else{
381 $is_new = false;
382 }
384 /* if parameter removed is true, we have to add FAIstate to the current attrs
385 FAIstate should end with ...|removed after this operation */
386 if($removed ){
387 $ldap->cat($Current_DN);
389 /* Get current object, because we must add the FAIstate ...|removed */
390 if((!$ldap->count()) && !empty($parent_obj)){
391 $ldap->cat($parent_obj);
392 }
394 /* Check if we have found a suiteable object */
395 if(!$ldap->count()){
396 echo "Error can't remove this object ".$Current_DN;
397 return;
398 }else{
400 /* Set FAIstate to current objectAttrs */
401 $objectAttrs = FAI:: prepare_ldap_fetch_to_be_saved($ldap->fetch());
402 if(isset($objectAttrs['FAIstate'][0])){
403 if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
404 $objectAttrs['FAIstate'][0] .= "|removed";
405 }
406 }else{
407 $objectAttrs['FAIstate'][0] = "|removed";
408 }
410 /* Force reload of FAI classes */
411 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
412 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
413 $reload_fai_classes = TRUE;
414 }
415 }
416 }
418 /* Check if this a leaf release or not */
419 if(count($following_releases) == 0 ){
421 /* This is a leaf object. It isn't inherited by any other object */
422 if(DEBUG_FAI_FUNC) {
423 echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
424 print_a($objectAttrs);
425 }
426 FAI::save_FAI_object($Current_DN,$objectAttrs);
428 /* Force reload of FAI classes */
429 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
430 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
431 $reload_fai_classes = TRUE;
432 }
434 }else{
436 /* This object is inherited by some sub releases */
438 /* Get all releases, that inherit this object */
439 $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
441 /* Get parent object */
442 $ldap->cat($parent_obj);
443 $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
445 /* New objects require special handling */
446 if($is_new){
448 /* Force reload of FAI classes */
449 $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
450 if(count(array_intersect($classes,$objectAttrs['objectClass']))){
451 $reload_fai_classes = TRUE;
452 }
454 /* check if there is already an entry named like this,
455 in one of our parent releases */
456 if(!empty($parent_obj)){
457 if(DEBUG_FAI_FUNC) {
458 echo "There is already an entry named like this.</b><br>";
460 echo "<b>Saving main object</b>".$Current_DN;
461 print_a($objectAttrs);
462 }
463 FAI::save_FAI_object($Current_DN,$objectAttrs);
465 foreach($r as $key){
466 if(DEBUG_FAI_FUNC) {
467 echo "<b>Saving parent to following release</b> ".$key;
468 print_a($parent_attrs);
469 }
470 FAI::save_FAI_object($key,$parent_attrs);
471 }
472 }else{
474 if(DEBUG_FAI_FUNC) {
475 echo "<b>Saving main object</b>".$Current_DN;
476 print_a($objectAttrs);
477 }
478 FAI::save_FAI_object($Current_DN,$objectAttrs);
480 if(isset($objectAttrs['FAIstate'])){
481 $objectAttrs['FAIstate'] .= "|removed";
482 }else{
483 $objectAttrs['FAIstate'] = "|removed";
484 }
486 foreach($r as $key ){
487 if(DEBUG_FAI_FUNC) {
488 echo "<b>Create an empty placeholder in follwing release</b> ".$key;
489 print_a($objectAttrs);
490 }
491 FAI::save_FAI_object($key,$objectAttrs);
492 }
493 }
494 }else{
496 /* check if we must patch the follwing release */
497 if(!empty($r)){
499 foreach($r as $key ){
500 if(DEBUG_FAI_FUNC) {
501 echo "<b>Copy current objects original attributes to next release</b> ".$key;
502 print_a($parent_attrs);
503 }
505 /* Append FAIstate tag to ensure that freezed objects stay freezed
506 */
507 $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
508 $parent_attrs['FAIstate'] = $rTag;
509 FAI::save_FAI_object($key,$parent_attrs);
510 }
511 }
513 if(DEBUG_FAI_FUNC) {
514 echo "<b>Saving current object</b>".$parent_obj;
515 print_a($objectAttrs);
516 }
517 FAI::save_FAI_object($parent_obj,$objectAttrs);
519 if(($parent_obj != $Current_DN)){
520 msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
521 }
522 }
523 }
524 }
526 /* Reload GOsa si FAI DB/cache
527 */
528 if($reload_fai_classes){
529 if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
530 $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);
531 if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
532 $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'];
533 $tmp = new $evt['CLASS_NAME']($config);
534 $tmp->set_type(TRIGGERED_EVENT);
535 $tmp->add_targets(array("GOsa"));
536 $o_queue = new gosaSupportDaemon();
537 if(!$o_queue->append($tmp)){
538 msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
539 }
540 }
541 }
542 }
544 session::set('FAI_objects_to_save',array());
545 }
548 /* this function will remove all unused (deleted) objects,
549 that have no parent object */
550 static function clean_up_releases($Current_DN)
551 {
552 global $config;
553 $ldap = $config->get_ldap_link();
554 $ldap->cd($config->current['BASE']);
556 /* Collect some basic informations and initialize some variables */
557 $base_release = FAI::get_release_dn($Current_DN);
558 $previous_releases = array_reverse(FAI:: get_previous_releases_of_this_release($base_release,true));
559 $Kill = array();
560 $Skip = array();
562 /* We must also include the given release dn */
563 $previous_releases[] = $base_release;
565 /* Walk through all releases */
566 foreach($previous_releases as $release){
568 /* Get fai departments */
569 $deps_to_search = FAI::get_FAI_departments($release);
571 /* For every single department (ou=hoos,ou ..) */
572 foreach($deps_to_search as $fai_base){
574 /* Ldap search for fai classes specified in this release */
575 $ldap->cd($fai_base);
576 $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
578 /* check the returned objects, and add/replace them in our return variable */
579 while($attr = $ldap->fetch()){
581 $buffer = array();
582 # $name = str_ireplace($release,"",$attr['dn']);
583 $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
585 if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
587 /* Check if this object is required somehow */
588 if(!isset($Skip[$name])){
589 $Kill[$attr['dn']] = $attr['dn'];
590 }
591 }else{
593 /* This object is required (not removed), so do not
594 delete any following sub releases of this object */
595 $Skip[$name] = $attr['dn'];
596 }
597 }
598 }
599 }
600 return($Kill);
601 }
604 /* Remove numeric index and 'count' from ldap->fetch result */
605 static function prepare_ldap_fetch_to_be_saved($attrs)
606 {
607 foreach($attrs as $key => $value){
608 if(is_numeric($key) || ($key == "count") || ($key == "dn")){
609 unset($attrs[$key]);
610 }
611 if(is_array($value) && isset($value['count'])){
612 unset($attrs[$key]['count']);
613 }
614 }
615 return($attrs);
616 }
619 /* Save given attrs to specified dn*/
620 static function save_FAI_object($dn,$attrs)
621 {
622 global $config;
623 $ldap = $config->get_ldap_link();
624 $ldap->cd($config->current['BASE']);
625 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
626 $ldap->cd($dn);
628 $ldap->cat($dn,array("dn"));
629 if($ldap->count()){
631 /* Remove FAIstate*/
632 if(!isset($attrs['FAIstate'])){
633 $attrs['FAIstate'] = array();
634 }
636 $ldap->modify($attrs);
637 }else{
639 /* Unset description if empty */
640 if(empty($attrs['description'])){
641 unset($attrs['description']);
642 }
644 $ldap->add($attrs);
645 }
646 if (!$ldap->success()){
647 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
648 }
649 }
652 /* Return FAIstate freeze branch or "" for specified release department */
653 static function get_release_tag($dn)
654 {
655 global $config;
656 $ldap = $config->get_ldap_link();
657 $ldap->cd($dn);
658 $ldap->cat($dn,array("FAIstate"));
660 if($ldap->count()){
662 $attr = $ldap->fetch();
663 if(isset($attr['FAIstate'][0])){
664 if(preg_match("/freeze/",$attr['FAIstate'][0])){
665 return("freeze");
666 }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
667 return("branch");
668 }
669 }
670 }
671 return("");
672 }
675 static function get_following_releases_that_inherit_this_object($dn)
676 {
677 global $config;
678 $ldap = $config->get_ldap_link();
679 $ldap->cd($config->current['BASE']);
681 $ret = array();
683 /* Get base release */
684 $base_release = FAI::get_release_dn($dn);
686 /* Get previous release dns */
687 $sub_releases = FAI:: get_sub_releases_of_this_release($base_release);
689 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
690 # $dn_suffix = str_ireplace($base_release,"",$dn);
691 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
693 /* Check if given object also exists whitin one of these releases */
694 foreach($sub_releases as $p_release => $name){
696 $check_dn = $dn_suffix.$p_release;
698 $ldap->cat($check_dn,array("dn","objectClass"));
700 if($ldap->count()){
701 //return($ret);
702 }else{
703 $ret[$check_dn]=$check_dn;
704 }
705 }
706 return($ret);
707 }
710 /* Get previous version of the object dn */
711 static function get_parent_release_object($dn,$include_myself=true)
712 {
713 global $config;
714 $ldap = $config->get_ldap_link();
715 $ldap->cd($config->current['BASE']);
716 $previous_releases= array();
718 /* Get base release */
719 $base_release = FAI::get_release_dn($dn);
720 if($include_myself){
721 $previous_releases[] = $base_release;
722 }
724 /* Get previous release dns */
725 $tmp = FAI:: get_previous_releases_of_this_release($base_release,true);
726 foreach($tmp as $release){
727 $previous_releases[] = $release;
728 }
730 /* Get dn suffix. Example "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
731 # $dn_suffix = str_ireplace($base_release,"",$dn);
732 $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
734 /* Check if given object also exists whitin one of these releases */
735 foreach($previous_releases as $p_release){
736 $check_dn = $dn_suffix.$p_release;
737 $ldap->cat($check_dn,array("dn","objectClass"));
739 if($ldap->count()){
740 return($check_dn);
741 }
742 }
743 return("");
744 }
747 /* return release names of all parent releases */
748 static function get_previous_releases_of_this_release($dn,$flat)
749 {
750 global $config;
751 $ldap = $config->get_ldap_link();
752 $ldap->cd($config->current['BASE']);
753 $ret = array();
755 /* Explode dns into pieces, to be able to build parent dns */
756 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
758 if(!is_array($dns_to_check)){
759 return;
760 }
762 /* Unset first entry which represents the given dn */
763 unset($dns_to_check['count']);
764 unset($dns_to_check[key($dns_to_check)]);
766 /* Create dns addresses and check if this dn is a release dn */
767 $id = 0;
768 while(count($dns_to_check)){
770 /* build parent dn */
771 $new_dn = "";
772 foreach($dns_to_check as $part){
773 $new_dn .= $part.",";
774 }
775 $new_dn .= $config->current['BASE'];
777 /* check if this dn is a release */
778 if(FAI::is_release_department($new_dn)){
779 if($flat){
780 $ret[$id] = $new_dn;
781 }else{
782 $ret = array($new_dn=>$ret);
783 }
784 $id ++;
785 }else{
786 return($ret);
787 }
788 reset($dns_to_check);
789 unset($dns_to_check[key($dns_to_check)]);
790 }
791 return($ret);
792 }
795 /* This function returns all sub release names, recursivly */
796 static function get_sub_releases_of_this_release($dn,$flat = false)
797 {
798 global $config;
799 $res = array();
800 $ldap = $config->get_ldap_link();
801 $ldap->cd($config->current['BASE']);
802 $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
803 while($attr = $ldap->fetch()){
805 /* Append department name */
806 if($flat){
807 $res[$attr['dn']] = $attr['ou'][0];
808 }else{
809 $res[$attr['dn']] = array();
810 }
812 /* Get sub release departments of this department */
813 if(in_array("FAIbranch",$attr['objectClass'])) {
814 if($flat){
815 $tmp = FAI:: get_sub_releases_of_this_release($attr['dn'],$flat);
816 foreach($tmp as $dn => $value){
817 $res[$dn]=$value;
818 }
819 }else{
820 $res[$attr['dn']] = FAI:: get_sub_releases_of_this_release($attr['dn']);
821 }
822 }
823 }
824 return($res);
825 }
828 /* Check if the given department is a release department */
829 static function is_release_department($dn)
830 {
831 global $config;
832 $ldap = $config->get_ldap_link();
833 $ldap->cd($config->current['BASE']);
834 $ldap->cat($dn,array("objectClass","ou"));
836 /* Check objectClasses and name to check if this is a release department */
837 if($ldap->count()){
838 $attrs = $ldap->fetch();
840 $ou = "";
841 if(isset($attrs['ou'][0])){
842 $ou = $attrs['ou'][0];
843 }
845 if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
846 return($attrs['dn']);
847 }
848 }
849 return(false);
850 }
853 static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
854 {
855 global $config;
856 $start = microtime(TRUE);
857 $source_release = trim($source_release,"/");
859 echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
861 $sub_releases = array();
862 $source_dn = "";
864 $tmp = split("\/",$source_release);
865 foreach($tmp as $part){
866 if(empty($part)){
867 continue;
868 }
869 $source_dn = "ou=".$part.",".$source_dn;
870 $sub_releases[$part] = $source_dn;
871 }
873 /* Get all groups */
874 $ldap =$config->get_ldap_link();
875 $ldap->cd($config->current['BASE']);
876 $ldap->search("(objectClass=posixGroup)",array("dn"));
877 $groups = array();
878 while($attrs = $ldap->fetch()){
879 $groups[$attrs['dn']] = $attrs;
880 }
882 /* Get all FAI releases, to be able to create missing group application releases
883 with the correct type of release (FAIstate=freeze/branch).
884 */
885 $f_releases = array();
886 $ldap->cd ($config->current['BASE']);
887 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
888 while($attrs = $ldap->fetch()){
889 foreach($sub_releases as $sub_rel){
890 if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
891 $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
892 }
893 }
894 }
896 /* Get all group releases */
897 $g_releases = array();
898 foreach($groups as $dn => $data){
899 $ldap->cd($dn);
900 $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
901 while($attrs = $ldap->fetch()){
902 $g_releases[$attrs['dn']] = $attrs;
903 }
904 }
906 /* Check if base releases exists.
907 If they do not exist, create them and adapt FAIstate attribute from FAI releases.
908 */
909 foreach($sub_releases as $name => $sub_rel){
911 $FAIstate = "";
912 if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
913 $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
914 }
916 foreach($groups as $dn => $data){
917 if(!isset($g_releases[$sub_rel.$dn])){
918 $ldap->cd($dn);
919 $r_data = array();
920 $r_data['ou'] = $name;
921 $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
922 if(!empty($FAIstate)) {
923 $r_data['FAIstate'] = $FAIstate;
924 }
926 $ldap->cd($sub_rel.$dn) ;
927 $ldap->add($r_data);
928 echo " <b>"._("Object").":</b> ";
929 echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
930 flush();
931 }
932 }
933 }
935 /* Create new release container in each group.
936 */
937 $n_data = array();
938 $n_data = array();
939 $n_data['ou'] = $destination_name;
940 $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
941 if(!empty($type)){
942 $n_data['FAIstate'] = $type."/cow";
943 }
945 foreach($groups as $dn => $att){
946 $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
947 if(!isset($g_releases[$n_dn])){
948 $ldap->cd ($n_dn);
949 $ldap->add($n_data);
950 echo " <b>"._("Object").":</b> ";
951 echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
952 flush();
953 }
954 }
956 /* If the source release is empty, then create a new release by copying
957 all group application menus into a new ou=$destination_name release container.
959 If the source release is not empty.
960 We detect all releases which match the source release dn and copy the contents.
961 */
962 if(empty($source_release)){
963 $source_dns = $groups;
964 }else{
965 $source_dns = array();
966 foreach($g_releases as $dn => $data){
967 if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
968 $source_dns[$dn] = $data;
969 }
970 }
971 }
973 /* Detect all menu object we have to copy
974 */
975 $to_copy = array();
976 foreach($source_dns as $dn => $attrs){
977 $ldap->cd($dn);
978 $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
979 while($attrs = $ldap->fetch()){
980 $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
981 $to_copy[$attrs['dn']] = $destination;
982 }
983 }
985 /* At least create the menu objects object */
986 $plug = new plugin($config);
987 foreach($to_copy as $source => $destination){
988 $ldap->cat($destination);
989 if($ldap->count()){
990 echo " <b>"._("Object").":</b> ";
991 echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
992 flush();
993 }else{
994 $plug->copy($source,$destination);
995 echo " <b>"._("Object").":</b> ";
996 echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
997 flush();
998 }
999 }
1000 }
1003 /*! \brief Create a new FAI branch.
1004 * @param $sourcedn String The source release dn
1005 * @param $destinationdn String The destination dn
1006 * @param $destinationName String The name of the new release
1007 * @param $type String The release type (freeze/branch)
1008 * @param $is_first Boolean Use to identify the first func. call when recursivly called.
1009 * @param $depth Integer Current depth of recursion.
1010 */
1011 static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1012 {
1013 global $config;
1014 error_reporting(E_ALL | E_STRICT);
1015 $ldap = $config->get_ldap_link();
1016 $basedn = $config->current['BASE'];
1017 $delarray = array();
1019 /* The following code will output a status string
1020 * for each handled object, in a seperate iframe.
1021 */
1024 /* Display current action information.
1025 */
1026 if($is_first){
1027 echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1028 }else{
1029 if(preg_match("/^ou=/",$sourcedn)){
1030 echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1031 }else{
1032 $tmp = split(",",$sourcedn);
1033 echo " <b>"._("Object").":</b> ";
1034 $deststr = LDAP::fix($destinationdn);
1035 if(strlen($deststr) > 96){
1036 $deststr = substr($deststr,0,96)."...";
1037 }
1038 echo $deststr."<br>";
1039 }
1040 }
1041 /* .. immediately display infos */
1042 flush();
1044 /* Check if destination entry already exists
1045 */
1046 $ldap->cat($destinationdn);
1047 if($ldap->count()){
1048 echo _("Could not create new release, the destination dn is already in use.");
1049 return;
1050 }else{
1052 $ldap->clearResult();
1054 /* Get source entry
1055 * if it does not exist, abort here.
1056 */
1057 $ldap->cd($basedn);
1058 $ldap->cat($sourcedn);
1059 $attr = $ldap->fetch();
1060 if((!$attr) || (count($attr)) ==0) {
1061 echo _("Error while fetching source dn - aborted!");
1062 return;
1063 }
1065 /* The current object we want to create is an department.
1066 * Create the department and add the FAIbranch tag.
1067 */
1068 if(in_array("organizationalUnit",$attr['objectClass'])){
1069 $attr['dn'] = LDAP::convert($destinationdn);
1070 $ldap->cd($basedn);
1071 $ldap->create_missing_trees($destinationdn);
1072 $ldap->cd($destinationdn);
1074 /* If is first entry, append FAIbranch to department entry */
1075 if($is_first){
1076 $ldap->cat($destinationdn);
1077 $attr= $ldap->fetch();
1078 /* Filter unneeded informations */
1079 foreach($attr as $key => $value){
1080 if(is_numeric($key)) unset($attr[$key]);
1081 if(isset($attr[$key]['count'])){
1082 if(is_array($attr[$key])){
1083 unset($attr[$key]['count']);
1084 }
1085 }
1086 }
1088 unset($attr['count']);
1089 unset($attr['dn']);
1091 /* Add marking attribute */
1092 $attr['objectClass'][] = "FAIbranch";
1093 $attr['FAIstate'] = $type;
1095 /* Add this entry */
1096 $ldap->modify($attr);
1097 }
1098 }else{
1100 /* Replicate all relevant FAI objects here.
1101 * FAI objects, Apps and Mimetypes.
1102 * Get all attributes as binary value, to ensure that Icon, File template aso
1103 * are created correctly.
1104 */
1105 foreach($attr as $key => $value){
1107 if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1108 $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1109 $ei= ldap_first_entry($ldap->cid, $sr);
1110 if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1111 $attr[$key] = $tmp;
1112 }
1113 }
1115 if(is_numeric($key)) unset($attr[$key]);
1116 if(isset($attr[$key]['count'])){
1117 if(is_array($attr[$key])){
1118 unset($attr[$key]['count']);
1119 }
1120 }
1121 }
1122 unset($attr['count']);
1123 unset($attr['dn']);
1124 if(!in_array("FAIclass",$attr['objectClass'])){
1125 $attr['objectClass'][] = "FAIobject";
1126 }
1127 $attr['FAIstate'] = $type;
1129 /* Add entry
1130 */
1131 $ldap->cd($destinationdn);
1132 $ldap->cat($destinationdn);
1134 $a = $ldap->fetch();
1135 if(!count($a)){
1136 $ldap->add($attr);
1137 }
1139 if(!$ldap->success()){
1141 /* Some error occurred */
1142 print "---------------------------------------------";
1143 print $ldap->get_error()."<br>";
1144 print $sourcedn."<br>";
1145 print $destinationdn."<br>";
1146 print_a( $attr);
1147 exit();
1148 }
1149 }
1150 }
1152 echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1154 /* Prepare for recursive copy.
1155 * Get all object within the source dn and
1156 * call the recursive copy for each.
1157 */
1158 $ldap->ls ("(objectClass=*)",$sourcedn);
1159 while ($ldap->fetch()){
1160 $deldn= $ldap->getDN();
1161 $delarray[$deldn]= strlen($deldn);
1162 }
1163 asort ($delarray);
1164 reset ($delarray);
1165 $depth ++;
1166 foreach($delarray as $dn => $bla){
1167 if($dn != $destinationdn){
1168 $ldap->cd($basedn);
1169 $item = $ldap->fetch($ldap->cat($dn));
1170 if(!in_array("FAIbranch",$item['objectClass'])){
1171 FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1172 }
1173 }
1174 }
1175 if($is_first){
1176 echo "<p class='seperator'> </p>";
1177 }
1178 }
1182 /* This function returns the dn of the object release */
1183 static function get_release_dn($Current_DN)
1184 {
1185 global $config;
1186 $ldap = $config->get_ldap_link();
1187 $ldap->cd($config->current['BASE']);
1189 /* Split dn into pices */
1190 $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1192 if(!is_array($dns_to_check)){
1193 return;
1194 }
1196 /* Use dn pieces, to create sub dns like
1197 ou=test,ou=1,ou=0...
1198 ou=1,ou=0...
1199 ou=0...
1200 To check which dn is our release container.
1201 */
1202 unset($dns_to_check['count']);
1203 while(count($dns_to_check)){
1205 /* Create dn */
1206 $new_dn = "";
1207 foreach($dns_to_check as $part){
1208 $new_dn .= $part.",";
1209 }
1210 $new_dn .= $config->current['BASE'];
1212 /* Check if this dn is a release dn */
1213 if(FAI::is_release_department($new_dn)){
1214 return($new_dn);
1215 }
1217 /* Remove first element of dn pieces */
1218 reset($dns_to_check);
1219 unset($dns_to_check[key($dns_to_check)]);
1220 }
1221 return("");
1222 }
1223 }
1228 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1229 ?>