1 <?php
3 /*
4 This code is part of GOsa (https://gosa.gonicus.de)
5 Copyright (C) 2007 Fabian Hickert
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
24 /****************
25 * FUNCTIONS
27 Step_Migrate - Constructor.
28 update_strings - Used to update the displayed step informations.
29 initialize_checks - Initialize migration steps.
30 check_ldap_permissions - Check if the used admin account has full access to the ldap database.
31 check_gosaAccounts - Check if there are users without the required objectClasses.
32 migrate_gosaAccounts - Migrate selected users to GOsa user accounts.
33 check_organizationalUnits - Check if there are departments, that are not visible for GOsa
34 migrate_organizationalUnits - Migrate selected departments
35 check_administrativeAccount - Check if there is at least one acl entry available
36 checkBase - Check if there is a root object available
38 get_user_list - Get list of available users
39 get_group_list - Get list of groups
41 create_admin
42 create_admin_user
44 execute - Generate html output of this plugin
45 save_object - Save posts
46 array_to_ldif - Create ldif output of an ldap result array
48 ****************/
52 class Step_Migrate extends setup_step
53 {
54 var $languages = array();
55 var $attributes = array();
56 var $header_image = "images/monitoring.png";
57 var $checks = array();
59 /* Department migration attributes */
60 var $dep_migration_dialog = FALSE;
61 var $deps_to_migrate = array();
62 var $show_details = FALSE;
64 /* Department migration attributes */
65 var $users_migration_dialog= FALSE;
66 var $users_to_migrate = array();
68 /* Create Acl attributes */
69 var $acl_create_dialog = FALSE;
70 var $acl_create_selected= ""; // Currently selected element, that should receive admin rights
71 var $acl_create_changes = ""; // Contains ldif information about changes
72 var $acl_create_confirmed= FALSE;
74 /* Checks initialised ? */
75 var $checks_initialised = FALSE;
77 /* Users outside to people ou */
78 var $outside_users = array();
79 var $outside_users_dialog = FALSE;
81 /* Users outside to groups ou */
82 var $outside_groups = array();
83 var $outside_groups_dialog = FALSE;
85 /* Win-Workstations outside to reserved ou */
86 var $outside_winstations = array();
87 var $outside_winstations_dialog = FALSE;
89 /* check for multiple use of same uidNumber */
90 var $check_uidNumbers = array();
91 var $check_uidNumbers_dialog = FALSE;
93 /* check for multiple use of same gidNumber */
94 var $check_gidNumbers = array();
95 var $check_gidNumbers_dialog = FALSE;
97 var $group_list = array();
99 function Step_Migrate()
100 {
101 $this->update_strings();
102 }
104 function update_strings()
105 {
106 $this->s_title = _("LDAP inspection");
107 $this->s_title_long = _("LDAP inspection");
108 $this->s_info = _("Analyze your current LDAP for GOsa compatibility");
109 }
111 function initialize_checks()
112 {
113 $this->checks = array();
114 $this->checks['root']['TITLE'] = _("Checking for root object");
115 $this->checks['root']['STATUS'] = FALSE;
116 $this->checks['root']['STATUS_MSG']= "";
117 $this->checks['root']['ERROR_MSG'] = "";
118 $this->checkBase();
120 $this->checks['permissions']['TITLE'] = _("Checking permissions on LDAP database");
121 $this->checks['permissions']['STATUS'] = FALSE;
122 $this->checks['permissions']['STATUS_MSG']= "";
123 $this->checks['permissions']['ERROR_MSG'] = "";
124 $this->check_ldap_permissions();
126 $this->checks['deps_visible']['TITLE'] = _("Checking for invisible departments");
127 $this->checks['deps_visible']['STATUS'] = FALSE;
128 $this->checks['deps_visible']['STATUS_MSG']= "";
129 $this->checks['deps_visible']['ERROR_MSG'] = "";
131 $this->checks['users_visible']['TITLE'] = _("Checking for invisible users");
132 $this->checks['users_visible']['STATUS'] = FALSE;
133 $this->checks['users_visible']['STATUS_MSG']= "";
134 $this->checks['users_visible']['ERROR_MSG'] = "";
135 $this->check_gosaAccounts();
137 $this->checks['acls']['TITLE'] = _("Checking for super administrator");
138 $this->checks['acls']['STATUS'] = FALSE;
139 $this->checks['acls']['STATUS_MSG']= "";
140 $this->checks['acls']['ERROR_MSG'] = "";
141 $this->check_administrativeAccount();
143 $this->checks['outside_users']['TITLE'] = _("Checking for users outside the people tree");
144 $this->checks['outside_users']['STATUS'] = FALSE;
145 $this->checks['outside_users']['STATUS_MSG']= "";
146 $this->checks['outside_users']['ERROR_MSG'] = "";
147 $this->search_outside_users();
149 $this->checks['outside_groups']['TITLE'] = _("Checking for groups outside the groups tree");
150 $this->checks['outside_groups']['STATUS'] = FALSE;
151 $this->checks['outside_groups']['STATUS_MSG']= "";
152 $this->checks['outside_groups']['ERROR_MSG'] = "";
153 $this->search_outside_groups();
154 $this->check_organizationalUnits();
156 $this->checks['outside_winstations']['TITLE'] = _("Checking for windows workstations outside the winstation tree");
157 $this->checks['outside_winstations']['STATUS'] = FALSE;
158 $this->checks['outside_winstations']['STATUS_MSG']= "";
159 $this->checks['outside_winstations']['ERROR_MSG'] = "";
160 $this->search_outside_winstations();
162 $this->checks['uidNumber_usage']['TITLE'] = _("Checking for duplicated UID numbers");
163 $this->checks['uidNumber_usage']['STATUS'] = FALSE;
164 $this->checks['uidNumber_usage']['STATUS_MSG']= "";
165 $this->checks['uidNumber_usage']['ERROR_MSG'] = "";
166 $this->check_uidNumber();
168 $this->checks['gidNumber_usage']['TITLE'] = _("Checking for duplicate GID numbers");
169 $this->checks['gidNumber_usage']['STATUS'] = FALSE;
170 $this->checks['gidNumber_usage']['STATUS_MSG']= "";
171 $this->checks['gidNumber_usage']['ERROR_MSG'] = "";
172 $this->check_gidNumber();
173 }
176 /* Check if there are uidNumbers which are used more than once.
177 */
178 function check_uidNumber()
179 {
180 /* Establish ldap connection */
181 $cv = $this->parent->captured_values;
182 $ldap_l = new LDAP($cv['admin'],
183 $cv['password'],
184 $cv['connection'],
185 FALSE,
186 $cv['tls']);
188 $ldap = new ldapMultiplexer($ldap_l);
190 $ldap->cd($cv['base']);
191 $res = $ldap->search("(&(objectClass=posixAccount)(uidNumber=*))",array("dn","uidNumber"));
192 if(!$res){
193 $this->checks['uidNumber_usage']['STATUS'] = FALSE;
194 $this->checks['uidNumber_usage']['STATUS_MSG']= _("LDAP query failed");
195 $this->checks['uidNumber_usage']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
196 return(false);
197 }
199 $this->check_uidNumbers= array();
200 $tmp = array();
201 while($attrs = $ldap->fetch()){
202 $tmp[$attrs['uidNumber'][0]][] = $attrs;
203 }
205 foreach($tmp as $id => $entries){
206 if(count($entries) > 1){
207 foreach($entries as $entry){
208 $this->check_uidNumbers[base64_encode($entry['dn'])] = $entry;
209 }
210 }
211 }
213 if($this->check_uidNumbers){
214 $this->checks['uidNumber_usage']['STATUS'] = FALSE;
215 $this->checks['uidNumber_usage']['STATUS_MSG']= "<font style='color:#F0A500'>"._("Warning")."</font>";
216 $this->checks['uidNumber_usage']['ERROR_MSG'] =
217 sprintf(_("Found %s duplicate values for attribute 'uidNumber'."),count($this->check_uidNumbers));
218 return(false);
219 }else{
220 $this->checks['uidNumber_usage']['STATUS'] = TRUE;
221 $this->checks['uidNumber_usage']['STATUS_MSG']= _("Ok");
222 $this->checks['uidNumber_usage']['ERROR_MSG'] = "";
223 return(TRUE);
224 }
225 }
228 /* Check if there are duplicated gidNumbers present in ldap
229 */
230 function check_gidNumber()
231 {
232 /* Establish ldap connection */
233 $cv = $this->parent->captured_values;
234 $ldap_l = new LDAP($cv['admin'],
235 $cv['password'],
236 $cv['connection'],
237 FALSE,
238 $cv['tls']);
240 $ldap = new ldapMultiplexer($ldap_l);
242 $ldap->cd($cv['base']);
243 $res = $ldap->search("(&(objectClass=posixGroup)(gidNumber=*))",array("dn","gidNumber"));
244 if(!$res){
245 $this->checks['gidNumber_usage']['STATUS'] = FALSE;
246 $this->checks['gidNumber_usage']['STATUS_MSG']= _("LDAP query failed");
247 $this->checks['gidNumber_usage']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
248 return(false);
249 }
251 $this->check_gidNumbers= array();
252 $tmp = array();
253 while($attrs = $ldap->fetch()){
254 $tmp[$attrs['gidNumber'][0]][] = $attrs;
255 }
257 foreach($tmp as $id => $entries){
258 if(count($entries) > 1){
259 foreach($entries as $entry){
260 $this->check_gidNumbers[base64_encode($entry['dn'])] = $entry;
261 }
262 }
263 }
265 if($this->check_gidNumbers){
266 $this->checks['gidNumber_usage']['STATUS'] = FALSE;
267 $this->checks['gidNumber_usage']['STATUS_MSG']= "<font style='color:#F0A500'>"._("Warning")."</font>";
268 $this->checks['gidNumber_usage']['ERROR_MSG'] =
269 sprintf(_("Found %s duplicate values for attribute 'gidNumber'."),count($this->check_gidNumbers));
270 return(false);
271 }else{
272 $this->checks['gidNumber_usage']['STATUS'] = TRUE;
273 $this->checks['gidNumber_usage']['STATUS_MSG']= _("Ok");
274 $this->checks['gidNumber_usage']['ERROR_MSG'] = "";
275 return(TRUE);
276 }
277 }
280 /* Search for winstations outside the winstation ou
281 */
282 function search_outside_winstations()
283 {
284 /* Establish ldap connection */
285 $cv = $this->parent->captured_values;
286 $ldap_l = new LDAP($cv['admin'],
287 $cv['password'],
288 $cv['connection'],
289 FALSE,
290 $cv['tls']);
292 $ldap = new ldapMultiplexer($ldap_l);
294 /* Get winstation ou */
295 if($cv['generic_settings']['wws_ou_active']) {
296 $winstation_ou = $cv['generic_settings']['ws_ou'];
297 }else{
298 $winstation_ou = "ou=winstations";
299 }
301 if($cv['samba_version'] == 3){
302 $oc = "sambaSamAccount";
303 }else{
304 $oc = "sambaAccount";
305 }
307 $ldap->cd($cv['base']);
308 $res = $ldap->search("(&(objectClass=".$oc.")(uid=*$))",array("dn","sambaSID"));
309 if(!$res){
310 $this->checks['outside_winstations']['STATUS'] = FALSE;
311 $this->checks['outside_winstations']['STATUS_MSG']= _("LDAP query failed");
312 $this->checks['outside_winstations']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
313 return(false);
314 }
316 $this->outside_winstations = array();
317 while($attrs = $ldap->fetch()){
318 if((!preg_match("/^[^,]+,".normalizePreg($winstation_ou)."/",$attrs['dn'])) && !preg_match("/,dc=addressbook,/",$attrs['dn'])){
319 $attrs['selected'] = FALSE;
320 $attrs['ldif'] = "";
321 $this->outside_winstations[base64_encode($attrs['dn'])] = $attrs;
322 }
323 }
325 if(count($this->outside_winstations)){
326 $this->checks['outside_winstations']['STATUS'] = FALSE;
327 $this->checks['outside_winstations']['STATUS_MSG']= _("Failed");
328 $this->checks['outside_winstations']['ERROR_MSG'] =
329 sprintf(_("Found %s winstations outside the predefined winstation department ou '%s'."),count($this->outside_winstations),$winstation_ou);
330 $this->checks['outside_winstations']['ERROR_MSG'].= "<input type='submit' name='outside_winstations_dialog' value='"._("Migrate")."...'>";
331 return(false);
332 }else{
333 $this->checks['outside_winstations']['STATUS'] = TRUE;
334 $this->checks['outside_winstations']['STATUS_MSG']= _("Ok");
335 $this->checks['outside_winstations']['ERROR_MSG'] = "";
336 return(TRUE);
337 }
338 }
341 /* Search for groups outside the group ou
342 */
343 function search_outside_groups()
344 {
345 /* Establish ldap connection */
346 $cv = $this->parent->captured_values;
347 $ldap_l = new LDAP($cv['admin'],
348 $cv['password'],
349 $cv['connection'],
350 FALSE,
351 $cv['tls']);
353 $ldap = new ldapMultiplexer($ldap_l);
355 $group_ou = $cv['groupou'];
356 $ldap->cd($cv['base']);
358 /***********
359 * Get all gosaDepartments to be able to
360 * validate correct ldap tree position of every single user
361 ***********/
362 $valid_deps = array();
363 $valid_deps['/'] = $cv['base'];
364 $ldap->search("(&(objectClass=gosaDepartment)(ou=*))",array("dn","ou"));
365 while($attrs = $ldap->fetch()){
366 $valid_deps[] = $attrs['dn'];
367 }
369 /***********
370 * Get all groups
371 ***********/
372 $res = $ldap->search("(objectClass=posixGroup)",array("dn"));
373 if(!$res){
374 $this->checks['outside_groups']['STATUS'] = FALSE;
375 $this->checks['outside_groups']['STATUS_MSG']= _("LDAP query failed");
376 $this->checks['outside_groups']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
377 return(false);
378 }
380 $this->outside_groups = array();
381 $this->groups_list = array();;
382 while($attrs = $ldap->fetch()){
383 $group_db_base = preg_replace("/^[^,]+,".normalizePreg($group_ou)."+,/i","",$attrs['dn']);
385 /* Check if entry is not an addressbook only user
386 * and verify that he is in a valid department
387 */
388 if( !preg_match("/".normalizePreg("dc=addressbook,")."/",$group_db_base) &&
389 !in_array($group_db_base,$valid_deps)
390 ){
391 $attrs['selected'] = FALSE;
392 $attrs['ldif'] = "";
393 $this->outside_groups[base64_encode($attrs['dn'])] = $attrs;
394 }
395 $this->group_list[] = $attrs['dn'];
396 }
398 if(count($this->outside_groups)){
399 $this->checks['outside_groups']['STATUS'] = FALSE;
400 $this->checks['outside_groups']['STATUS_MSG']= "<font style='color:#F0A500'>"._("Warning")."</font>";
401 $this->checks['outside_groups']['ERROR_MSG'] =
402 sprintf(_("Found %s groups outside the configured tree '%s'."),count($this->outside_groups),$group_ou);
403 $this->checks['outside_groups']['ERROR_MSG'].= " <input type='submit' name='outside_groups_dialog' value='"._("Move")."...'>";
404 return(false);
405 }else{
406 $this->checks['outside_groups']['STATUS'] = TRUE;
407 $this->checks['outside_groups']['STATUS_MSG']= _("Ok");
408 $this->checks['outside_groups']['ERROR_MSG'] = "";
409 return(TRUE);
410 }
411 }
413 /* Search for users outside the people ou
414 */
415 function search_outside_users()
416 {
417 /* Establish ldap connection */
418 $cv = $this->parent->captured_values;
419 $ldap_l = new LDAP($cv['admin'],
420 $cv['password'],
421 $cv['connection'],
422 FALSE,
423 $cv['tls']);
425 $ldap = new ldapMultiplexer($ldap_l);
426 $ldap->cd($cv['base']);
429 /***********
430 * Get all gosaDepartments to be able to
431 * validate correct ldap tree position of every single user
432 ***********/
433 $valid_deps = array();
434 $valid_deps['/'] = $cv['base'];
435 $ldap->search("(&(objectClass=gosaDepartment)(ou=*))",array("dn","ou"));
436 while($attrs = $ldap->fetch()){
437 $valid_deps[] = $attrs['dn'];
438 }
440 /***********
441 * Search for all users
442 ***********/
443 $res = $ldap->search("(&(objectClass=gosaAccount)(!(uid=*$)))",array("dn"));
444 if(!$res){
445 $this->checks['outside_users']['STATUS'] = FALSE;
446 $this->checks['outside_users']['STATUS_MSG']= _("LDAP query failed");
447 $this->checks['outside_users']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
448 return(false);
449 }
451 /***********
452 * Check if returned users are within a valid GOsa deparmtment. (peopleou,gosaDepartment,base)
453 ***********/
454 $this->outside_users = array();
455 $people_ou = trim($cv['peopleou']);
456 if(!empty($people_ou)){
457 $people_ou = $people_ou.",";
458 }
460 while($attrs = $ldap->fetch()){
461 $people_db_base = preg_replace("/^[^,]+,".normalizePreg($people_ou)."/i","",$attrs['dn']);
463 /* Check if entry is not an addressbook only user
464 * and verify that he is in a valid department
465 */
466 if( !preg_match("/".normalizePreg("dc=addressbook,")."/",$people_db_base) &&
467 !in_array($people_db_base,$valid_deps)
468 ){
469 $attrs['selected'] = FALSE;
470 $attrs['ldif'] = "";
471 $this->outside_users[base64_encode($attrs['dn'])] = $attrs;
472 }
473 }
475 if(count($this->outside_users)){
476 $this->checks['outside_users']['STATUS'] = FALSE;
477 $this->checks['outside_users']['STATUS_MSG']= "<font style='color:#F0A500'>"._("Warning")."</font>";
478 $this->checks['outside_users']['ERROR_MSG'] =
479 sprintf(_("Found %s user(s) outside the configured tree '%s'."),count($this->outside_users),$people_ou);
480 $this->checks['outside_users']['ERROR_MSG'].= "<input type='submit' name='outside_users_dialog' value='"._("Move")."...'>";
481 return(false);
482 }else{
483 $this->checks['outside_users']['STATUS'] = TRUE;
484 $this->checks['outside_users']['STATUS_MSG']= _("Ok");
485 $this->checks['outside_users']['ERROR_MSG'] = "";
486 return(TRUE);
487 }
488 }
491 /* Check ldap accessibility
492 * Create and remove a dummy object,
493 * to ensure that we have the necessary permissions
494 */
495 function check_ldap_permissions()
496 {
497 /* Establish ldap connection */
498 $cv = $this->parent->captured_values;
499 $ldap_l = new LDAP($cv['admin'],
500 $cv['password'],
501 $cv['connection'],
502 FALSE,
503 $cv['tls']);
505 $ldap = new ldapMultiplexer($ldap_l);
507 /* Create dummy entry
508 */
509 $name = "GOsa_setup_text_entry_".session_id().rand(0,999999);
510 $dn = "ou=".$name.",".$cv['base'];
511 $testEntry= array();
512 $testEntry['objectClass'][]= "top";
513 $testEntry['objectClass'][]= "organizationalUnit";
514 $testEntry['objectClass'][]= "gosaDepartment";
515 $testEntry['description']= "Created by GOsa setup, this object can be removed.";
516 $testEntry['ou'] = $name;
518 /* check if simple ldap cat will be successful
519 */
520 $res = $ldap->cat($cv['base']);
521 if(!$res){
522 $this->checks['permissions']['STATUS'] = FALSE;
523 $this->checks['permissions']['STATUS_MSG']= _("LDAP query failed");
524 $this->checks['permissions']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
525 return(false);
526 }
528 /* Try to create dummy object
529 */
530 $ldap->cd ($dn);
531 $ldap->create_missing_trees($dn);
532 $res = $ldap->add($testEntry);
533 $ldap->cat($dn);
534 if(!$ldap->count()){
535 new log("view","setup/".get_class($this),$dn,array(),$ldap->get_error());
537 $this->checks['permissions']['STATUS'] = FALSE;
538 $this->checks['permissions']['STATUS_MSG']= _("Failed");
539 $this->checks['permissions']['ERROR_MSG'] =
540 sprintf(_("The specified user '%s' does not have full access to your ldap database."),$cv['admin']);
541 return(false);
542 }
544 /* Try to remove created entry
545 */
546 $res = $ldap->rmDir($dn);
547 $ldap->cat($dn);
548 if($ldap->count()){
549 new log("view","setup/".get_class($this),$dn,array(),$ldap->get_error());
550 $this->checks['permissions']['STATUS'] = FALSE;
551 $this->checks['permissions']['STATUS_MSG']= _("Failed");
552 $this->checks['permissions']['ERROR_MSG'] =
553 sprintf(_("The specified user '%s' does not have full access to your ldap database."),$cv['admin']);
554 return(false);
555 }
557 /* Create & remove of dummy object was successful */
558 $this->checks['permissions']['STATUS'] = TRUE;
559 $this->checks['permissions']['STATUS_MSG']= _("Ok");
560 $this->checks['permissions']['ERROR_MSG'] = "";
561 return(true);
562 }
565 /* Check if there are users which will
566 * be invisible for GOsa
567 */
568 function check_gosaAccounts()
569 {
570 /* Remember old list of ivisible users, to be able to set
571 * the 'html checked' status for the checkboxes again
572 */
573 $cnt_ok = 0;
574 $old = $this->users_to_migrate;
575 $this->users_to_migrate = array();
577 /* Establish ldap connection */
578 $cv = $this->parent->captured_values;
579 $ldap_l = new LDAP($cv['admin'],
580 $cv['password'],
581 $cv['connection'],
582 FALSE,
583 $cv['tls']);
585 $ldap = new ldapMultiplexer($ldap_l);
587 /* Get all invisible users
588 */
589 $ldap->cd($cv['base']);
590 $res =$ldap->search("(&(|(objectClass=posixAccount)(&(objectClass=inetOrgPerson)(objectClass=organizationalPerson)))(!(objectClass=gosaAccount))(uid=*))",array("sn","givenName","cn","uid"));
591 while($attrs = $ldap->fetch()){
592 if(!preg_match("/,dc=addressbook,/",$attrs['dn'])){
593 $attrs['checked'] = FALSE;
594 $attrs['before'] = "";
595 $attrs['after'] = "";
597 /* Set objects to selected, that were selected before reload */
598 if(isset($old[base64_encode($attrs['dn'])])){
599 $attrs['checked'] = $old[base64_encode($attrs['dn'])]['checked'];
600 }
601 $this->users_to_migrate[base64_encode($attrs['dn'])] = $attrs;
602 }
603 }
605 /* No invisible */
606 if(!$res){
607 $this->checks['users_visible']['STATUS'] = FALSE;
608 $this->checks['users_visible']['STATUS_MSG']= _("LDAP query failed");
609 $this->checks['users_visible']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
610 }elseif(count($this->users_to_migrate) == 0){
611 $this->checks['users_visible']['STATUS'] = TRUE;
612 $this->checks['users_visible']['STATUS_MSG']= _("Ok");
613 $this->checks['users_visible']['ERROR_MSG'] = "";
614 }else{
615 $this->checks['users_visible']['STATUS'] = FALSE;
616 $this->checks['users_visible']['STATUS_MSG']= "<font style='color:#F0A500'>"._("Warning")."</font>";
617 $this->checks['users_visible']['ERROR_MSG'] = sprintf(_("Found %s user(s) that will not be visible in GOsa."),
618 count($this->users_to_migrate));
619 $this->checks['users_visible']['ERROR_MSG'] .= "<input type='submit' name='users_visible_migrate' value='"._("Migrate")."...'>";
620 }
621 }
624 /* Start user account migration
625 */
626 function migrate_gosaAccounts($only_ldif = FALSE)
627 {
628 $this->show_details= $only_ldif;
630 /* Establish ldap connection */
631 $cv = $this->parent->captured_values;
632 $ldap_l = new LDAP($cv['admin'],
633 $cv['password'],
634 $cv['connection'],
635 FALSE,
636 $cv['tls']);
638 $ldap = new ldapMultiplexer($ldap_l);
640 /* Add gosaAccount objectClass to the selected users
641 */
642 foreach($this->users_to_migrate as $key => $dep){
643 if($dep['checked']){
645 /* Get old objectClasses */
646 $ldap->cat($dep['dn'],array("objectClass"));
647 $attrs = $ldap->fetch();
649 /* Create new objectClass array */
650 $new_attrs = array();
651 $new_attrs['objectClass']= array("gosaAccount","inetOrgPerson","organizationalPerson");
652 for($i = 0 ; $i < $attrs['objectClass']['count']; $i ++ ){
653 if(!in_array_ics($attrs['objectClass'][$i], $new_attrs['objectClass'])){
654 $new_attrs['objectClass'][] = $attrs['objectClass'][$i];
655 }
656 }
658 /* Set info attributes for current object,
659 * or write changes to the ldap database
660 */
661 if($only_ldif){
662 $this->users_to_migrate[$key]['before'] = $this->array_to_ldif($attrs);
663 $this->users_to_migrate[$key]['after'] = $this->array_to_ldif($new_attrs);
664 }else{
665 $ldap->cd($attrs['dn']);
666 if(!$ldap->modify($new_attrs)){
667 msg_dialog::display(_("Migration error"), sprintf(_("Cannot migrate department '%s':")."<br><br><i>%s</i>",LDAP::fix($attrs['dn']),$ldap->get_error()), ERROR_DIALOG);
668 return(false);
669 }
670 }
671 }
672 }
673 return(TRUE);
674 }
677 /* Check if there are invisible organizational Units
678 */
679 function check_organizationalUnits()
680 {
681 $cnt_ok = 0;
682 $old = $this->deps_to_migrate;
683 $this->deps_to_migrate = array();
685 /* Establish ldap connection */
686 $cv = $this->parent->captured_values;
687 $ldap_l = new LDAP($cv['admin'],
688 $cv['password'],
689 $cv['connection'],
690 FALSE,
691 $cv['tls']);
693 $ldap = new ldapMultiplexer($ldap_l);
695 /* Skip GOsa internal departments */
696 $skip_dns = array("/".$cv['peopleou']."/","/".$cv['groupou']."/","/^ou=people,/","/^ou=groups,/","/^ou=sudoers,/",
697 "/(,|)ou=configs,/","/(,|)ou=systems,/",
698 "/(,|)ou=apps,/","/(,|)ou=mime,/","/(,|)ou=devices/","/^ou=aclroles,/","/^ou=incoming,/",
699 "/ou=snapshots,/","/(,|)dc=addressbook,/","/^(,|)ou=machineaccounts,/",
700 "/(,|)ou=winstations,/");
702 /* Get all invisible departments */
703 $ldap->cd($cv['base']);
704 $res = $ldap->search("(&(objectClass=organizationalUnit)(!(objectClass=gosaDepartment)))",array("ou","description","dn"));
705 while($attrs = $ldap->fetch()){
706 $attrs['checked'] = FALSE;
707 $attrs['before'] = "";
708 $attrs['after'] = "";
710 /* Set objects to selected, that were selected before reload */
711 if(isset($old[base64_encode($attrs['dn'])])){
712 $attrs['checked'] = $old[base64_encode($attrs['dn'])]['checked'];
713 }
714 $this->deps_to_migrate[base64_encode($attrs['dn'])] = $attrs;
715 }
717 /* Filter returned list of departments and ensure that
718 * GOsa internal departments will not be listed
719 */
720 foreach($this->deps_to_migrate as $key => $attrs){
721 $dn = $attrs['dn'];
722 $skip = false;;
724 /* Check if this object is an application release object
725 e.g. groups-> application menus.
726 */
727 if(preg_match("/^.*,[ ]*cn=/",$dn)){
728 $cn_dn = preg_replace("/^.*,[ ]*cn=/","cn=",$dn);
729 if(in_array($cn_dn,$this->group_list)){
730 $skip = true;
731 }
732 }
734 foreach($skip_dns as $skip_dn){
735 if(preg_match($skip_dn,$dn)){
736 $skip = true;
737 }
738 }
739 if($skip){
740 unset($this->deps_to_migrate[$key]);
741 }
742 }
744 /* If we have no invisible departments found
745 * tell the user that everything is ok
746 */
747 if(!$res){
748 $this->checks['deps_visible']['STATUS'] = FALSE;
749 $this->checks['deps_visible']['STATUS_MSG']= _("LDAP query failed");
750 $this->checks['deps_visible']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
751 }elseif(count($this->deps_to_migrate) == 0 ){
752 $this->checks['deps_visible']['STATUS'] = TRUE;
753 $this->checks['deps_visible']['STATUS_MSG']= _("Ok");
754 $this->checks['deps_visible']['ERROR_MSG'] = "";
755 }else{
756 $this->checks['deps_visible']['STATUS'] = TRUE;
757 $this->checks['deps_visible']['STATUS_MSG']= '<font style="color:#FFA500">'._("Warning").'</font>';
758 $this->checks['deps_visible']['ERROR_MSG'] = sprintf(_("Found %s department(s) that will not be visible in GOsa."),count($this->deps_to_migrate));
759 $this->checks['deps_visible']['ERROR_MSG'] .= " <input type='submit' name='deps_visible_migrate' value='"._("Migrate")."...'>";
760 }
761 }
765 /* Start deparmtment migration */
766 function migrate_organizationalUnits($only_ldif = FALSE)
767 {
768 $this->show_details= $only_ldif;
770 /* Establish ldap connection */
771 $cv = $this->parent->captured_values;
772 $ldap_l = new LDAP($cv['admin'],
773 $cv['password'],
774 $cv['connection'],
775 FALSE,
776 $cv['tls']);
778 $ldap = new ldapMultiplexer($ldap_l);
780 /* Add gosaDepartment objectClass to each selected entry
781 */
782 foreach($this->deps_to_migrate as $key => $dep){
783 if($dep['checked']){
785 /* Get current objectClasses */
786 $ldap->cat($dep['dn'],array("objectClass","description"));
787 $attrs = $ldap->fetch();
789 /* Create new objectClass attribute including gosaDepartment*/
790 $new_attrs = array();
791 for($i = 0 ; $i < $attrs['objectClass']['count']; $i ++ ){
792 $new_attrs['objectClass'][] = $attrs['objectClass'][$i];
793 }
794 $new_attrs['objectClass'][] = "gosaDepartment";
796 /* Append description it is missing */
797 if(!isset($attrs['description'])){
798 $new_attrs['description'][] = "GOsa department";
799 }
801 /* Depending on the parameter >only_diff< we save the changes as ldif
802 * or we write our changes directly to the ldap database
803 */
804 if($only_ldif){
805 $this->deps_to_migrate[$key]['before'] = $this->array_to_ldif($attrs);
806 $this->deps_to_migrate[$key]['after'] = $this->array_to_ldif($new_attrs);
807 }else{
808 $ldap->cd($attrs['dn']);
809 if(!$ldap->modify($new_attrs)){
810 msg_dialog::display(_("Migration error"), sprintf(_("Cannot migrate department '%s':")."<br><br><i>%s</i>",LDAP::fix($attrs['dn']), $ldap->get_error()), ERROR_DIALOG);
811 return(false);
812 }
813 }
814 }
815 }
816 return(TRUE);
817 }
820 /* Check Acls if there is at least one object with acls defined
821 */
822 function check_administrativeAccount()
823 {
824 /* Establish ldap connection */
825 $cv = $this->parent->captured_values;
826 $ldap_l = new LDAP($cv['admin'],
827 $cv['password'],
828 $cv['connection'],
829 FALSE,
830 $cv['tls']);
832 $ldap = new ldapMultiplexer($ldap_l);
833 $ldap->cd($cv['base']);
834 $res = $ldap->cat($cv['base']);
836 if(!$res){
837 $this->checks['acls']['STATUS'] = FALSE;
838 $this->checks['acls']['STATUS_MSG']= _("LDAP query failed");
839 $this->checks['acls']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
840 }else{
841 $found = false;
842 $username = "";
843 $attrs = $ldap->fetch();
844 if(isset($attrs['gosaAclEntry'])){
845 $acls = $attrs['gosaAclEntry'];
846 for($i = 0 ; $i < $acls['count'] ; $i++){
847 $acl = $acls[$i];
848 $tmp = split(":",$acl);
849 if($tmp[1] == "psub"){
850 $members = split(",",$tmp[2]);
851 foreach($members as $member){
852 $member = base64_decode($member);
854 /* Check if acl owner is a valid GOsa user account */
855 $ldap->cat($member,array("objectClass","uid","cn"));
856 $ret = $ldap->fetch();
858 if(isset($ret['objectClass']) && in_array("posixGroup",$ret['objectClass'])){
859 $found = TRUE;
860 $username .= "ACL-Group: ".$ret['cn'][0]."<br>";
861 }elseif(isset($ret['objectClass']) && in_array("gosaAccount",$ret['objectClass']) &&
862 in_array("organizationalPerson",$ret['objectClass']) &&
863 in_array("inetOrgPerson",$ret['objectClass'])){
864 $found = TRUE;
865 $username .= "ACL: ".$ret['uid'][0]."<br>";
866 }
867 }
868 }elseif($tmp[1] == "role"){
870 /* Check if acl owner is a valid GOsa user account */
871 $ldap->cat(base64_decode($tmp[2]),array("gosaAclTemplate"));
872 $ret = $ldap->fetch();
874 if(isset($ret['gosaAclTemplate'])){
875 $cnt = $ret['gosaAclTemplate']['count'];
876 for($e = 0 ; $e < $cnt ; $e++){
878 $a_str = $ret['gosaAclTemplate'][$e];
879 if(preg_match("/^[0-9]*:psub:/",$a_str) && preg_match("/:all;cmdrw$/",$a_str)){
881 $members = split(",",$tmp[3]);
882 foreach($members as $member){
883 $member = base64_decode($member);
885 /* Check if acl owner is a valid GOsa user account */
886 $ldap->cat($member,array("objectClass","uid"));
887 $ret = $ldap->fetch();
889 if(isset($ret['objectClass']) && in_array("gosaAccount",$ret['objectClass']) &&
890 in_array("organizationalPerson",$ret['objectClass']) &&
891 in_array("inetOrgPerson",$ret['objectClass'])){
892 $found = TRUE;
893 $username .= "ACL Role: ".$ret['uid'][0]."<br>";
894 }
895 }
896 }
897 }
898 }
899 }
900 }
901 }
903 # For debugging
904 #echo $username;
906 if($found){
907 $this->checks['acls']['STATUS'] = TRUE;
908 $this->checks['acls']['STATUS_MSG']= _("Ok");
909 $this->checks['acls']['ERROR_MSG'] = "";
910 }else{
911 $this->checks['acls']['STATUS'] = FALSE;
912 $this->checks['acls']['STATUS_MSG']= _("Failed");
913 $this->checks['acls']['ERROR_MSG']= _("There is no GOsa administrator account inside your LDAP.")." ";
914 $this->checks['acls']['ERROR_MSG'].= "<input type='submit' name='create_acls' value='"._("Create")."'>";
915 }
916 }
917 return($ldap->count()>=1);
918 }
922 function create_admin($only_ldif = FALSE)
923 {
924 /* Reset '' */
925 $this->acl_create_changes="";
927 /* Object that should receive admin acls */
928 $dn = $this->acl_create_selected;
930 /* Get collected configuration settings */
931 $cv = $this->parent->captured_values;
933 /* On first call check for rid/sid base */
934 $ldap_l = new LDAP($cv['admin'],
935 $cv['password'],
936 $cv['connection'],
937 FALSE,
938 $cv['tls']);
940 $ldap = new ldapMultiplexer($ldap_l);
942 /* Get current base attributes */
943 $ldap->cd($cv['base']);
944 $ldap->cat($cv['base'],array("dn","objectClass","gosaAclEntry"));
945 $attrs = $ldap->fetch();
947 /* Add acls for the selcted user to the base */
948 $attrs_new = array();
949 $attrs_new['objectClass'] = array("gosaACL");
951 for($i = 0; $i < $attrs['objectClass']['count']; $i ++){
952 if(!in_array_ics($attrs['objectClass'][$i],$attrs_new['objectClass'])){
953 $attrs_new['objectClass'][] = $attrs['objectClass'][$i];
954 }
955 }
957 $acl = "0:psub:".base64_encode($dn).":all;cmdrw";
958 $attrs_new['gosaAclEntry'][] = $acl;
959 if(isset($attrs['gosaAclEntry'])){
960 for($i = 0 ; $i < $attrs['gosaAclEntry']['count']; $i ++){
962 $prio = preg_replace("/[:].*$/","",$attrs['gosaAclEntry'][$i]);
963 $rest = preg_replace("/^[^:]/","",$attrs['gosaAclEntry'][$i]);
965 $data = ($prio+1).$rest;
966 $attrs_new['gosaAclEntry'][] = $data;
967 }
968 }
970 if($only_ldif){
971 $this->acl_create_changes ="\n".($ldap->fix($cv['base']))."\n";
972 $this->acl_create_changes.=$this->array_to_ldif($attrs)."\n";
973 $this->acl_create_changes.="\n".($ldap->fix($cv['base']))."\n";
974 $this->acl_create_changes.=$this->array_to_ldif($attrs_new);
975 }else{
977 $ldap->cd($cv['base']);
978 if(!$ldap->modify($attrs_new)){
979 msg_dialog::display(_("Migration error"), sprintf(_("Cannot add ACL for user '%s':")."<br><br><i>%s</i>", LDAP::fix($dn), $ldap->get_error()), ERROR_DIALOG);
980 return(FALSE);
981 }else{
982 return(TRUE);
983 }
984 }
985 }
988 function create_admin_user()
989 {
990 $pw1 = $pw2 = "";
991 $uid = "";
993 if(isset($_POST['new_user_uid'])){
994 $uid = $_POST['new_user_uid'];
995 }
996 if(isset($_POST['new_user_password'])){
997 $pw1 = $_POST['new_user_password'];
998 }
999 if(isset($_POST['new_user_password2'])){
1000 $pw2 = $_POST['new_user_password2'];
1001 }
1003 if(empty($pw1) || empty($pw2) | ($pw1 != $pw2)){
1004 msg_dialog::display(_("Password error"), _("Provided passwords do not match!"), ERROR_DIALOG);
1005 return false;
1006 }
1008 if(!tests::is_uid($uid) || empty($uid)){
1009 msg_dialog::display(_("Input error"), _("Specify a valid user ID!"), ERROR_DIALOG);
1010 return false;
1011 }
1013 /* On first call check for rid/sid base */
1014 $cv = $this->parent->captured_values;
1015 $ldap_l = new LDAP($cv['admin'],
1016 $cv['password'],
1017 $cv['connection'],
1018 FALSE,
1019 $cv['tls']);
1021 $ldap = new ldapMultiplexer($ldap_l);
1023 /* Get current base attributes */
1024 $ldap->cd($cv['base']);
1026 $people_ou = trim($cv['peopleou']);
1027 if(!empty($people_ou)){
1028 $people_ou = trim($people_ou).",";
1029 }
1031 if($cv['peopledn'] == "cn"){
1032 $dn = "cn=System Administrator-".$uid.",".$people_ou.$cv['base'];
1033 }else{
1034 $dn = "uid=".$uid.",".$people_ou.$cv['base'];
1035 }
1037 $hash = passwordMethod::make_hash($pw2, $cv['encryption']);
1039 $new_user=array();
1040 $new_user['objectClass']= array("top","person","gosaAccount","organizationalPerson","inetOrgPerson");
1041 $new_user['givenName'] = "System";
1042 $new_user['sn'] = "Administrator";
1043 $new_user['cn'] = "System Administrator-".$uid;
1044 $new_user['uid'] = $uid;
1045 $new_user['userPassword'] = $hash;
1047 $ldap->cd($cv['base']);
1049 $ldap->cat($dn,array("dn"));
1050 if($ldap->count()){
1051 msg_dialog::display(_("Error"), sprintf(_("Adding an administrative user failed: object '%s' already exists!"), LDAP::fix($dn)), ERROR_DIALOG);
1052 return(FALSE);
1053 }
1055 $ldap->create_missing_trees(preg_replace("/^[^,]+,/","",$dn));
1056 $ldap->cd($dn);
1057 $res = $ldap->add($new_user);
1058 $this->acl_create_selected = $dn;
1059 $this->create_admin();
1061 if(!$res){
1062 msg_dialog::display(_("LDAP error"), $ldap->get_error(), ERROR_DIALOG);
1063 return(FALSE);
1064 }
1066 $this->acl_create_dialog=FALSE;
1067 $this->check_administrativeAccount();
1068 return(TRUE);
1069 }
1072 function migrate_outside_winstations($perform = FALSE)
1073 {
1074 /* Establish ldap connection */
1075 $cv = $this->parent->captured_values;
1076 $ldap_l = new LDAP($cv['admin'],
1077 $cv['password'],
1078 $cv['connection'],
1079 FALSE,
1080 $cv['tls']);
1082 $ldap = new ldapMultiplexer($ldap_l);
1084 $ldap->cd($cv['base']);
1086 /* Check if there was a destination department posted */
1087 if(isset($_POST['move_winstation_to'])){
1088 $destination_dep = $_POST['move_winstation_to'];
1089 }else{
1090 msg_dialog::display(_("LDAP error"), _("Cannot move users to the requested department!"), ERROR_DIALOG);
1091 return(false);
1092 }
1094 foreach($this->outside_winstations as $b_dn => $data){
1095 $this->outside_winstations[$b_dn]['ldif'] ="";
1096 if($data['selected']){
1097 $dn = base64_decode($b_dn);
1098 $d_dn = preg_replace("/,.*$/",",".base64_decode($destination_dep),$dn);
1099 if(!$perform){
1100 $this->outside_winstations[$b_dn]['ldif'] = _("Winstation will be moved from").":<br>\t".($ldap->fix($dn))."<br>"._("to").":<br>\t".($ldap->fix($d_dn));
1103 /* Check if there are references to this object */
1104 $ldap->search("(&(member=".LDAP::prepare4filter($dn).")(|(objectClass=gosaGroupOfNames)(objectClass=groupOfNames)))",array('dn'));
1105 $refs = "";
1106 while($attrs = $ldap->fetch()){
1107 $ref_dn = $attrs['dn'];
1108 $refs .= "<br />\t".$ref_dn;
1109 }
1110 if(!empty($refs)){
1111 $this->outside_winstations[$b_dn]['ldif'] .= "<br /><br /><i>"._("Updating following references too").":</i>".$refs;
1112 }
1114 }else{
1115 $this->move($dn,$d_dn);
1116 }
1117 }
1118 }
1119 }
1122 function migrate_outside_groups($perform = FALSE)
1123 {
1124 /* Establish ldap connection */
1125 $cv = $this->parent->captured_values;
1126 $ldap_l = new LDAP($cv['admin'],
1127 $cv['password'],
1128 $cv['connection'],
1129 FALSE,
1130 $cv['tls']);
1132 $ldap = new ldapMultiplexer($ldap_l);
1133 $ldap->cd($cv['base']);
1135 /* Check if there was a destination department posted */
1136 if(isset($_POST['move_group_to'])){
1137 $destination_dep = $_POST['move_group_to'];
1138 }else{
1139 msg_dialog::display(_("LDAP error"), _("Cannot move users to the requested department!"), ERROR_DIALOG);
1140 return(false);
1141 }
1143 foreach($this->outside_groups as $b_dn => $data){
1144 $this->outside_groups[$b_dn]['ldif'] ="";
1145 if($data['selected']){
1146 $dn = base64_decode($b_dn);
1147 $d_dn = preg_replace("/,.*$/",",".base64_decode($destination_dep),$dn);
1148 if(!$perform){
1150 $this->outside_groups[$b_dn]['ldif'] = _("Group will be moved from").":<br>\t".($ldap->fix($dn))."<br>"._("to").":<br>\t".($ldap->fix($d_dn));
1152 /* Check if there are references to this object */
1153 $ldap->search("(&(member=".LDAP::prepare4filter($dn).")(|(objectClass=gosaGroupOfNames)(objectClass=groupOfNames)))",array('dn'));
1154 $refs = "";
1155 while($attrs = $ldap->fetch()){
1156 $ref_dn = $attrs['dn'];
1157 $refs .= "<br />\t".$ref_dn;
1158 }
1159 if(!empty($refs)){
1160 $this->outside_groups[$b_dn]['ldif'] .= "<br /><br /><i>"._("Updating following references too").":</i>".$refs;
1161 }
1163 }else{
1164 $this->move($dn,$d_dn);
1165 }
1166 }
1167 }
1168 }
1171 function migrate_outside_users($perform = FALSE)
1172 {
1173 /* Establish ldap connection */
1174 $cv = $this->parent->captured_values;
1175 $ldap_l = new LDAP($cv['admin'],
1176 $cv['password'],
1177 $cv['connection'],
1178 FALSE,
1179 $cv['tls']);
1181 $ldap = new ldapMultiplexer($ldap_l);
1182 $ldap->cd($cv['base']);
1184 /* Check if there was a destination department posted */
1185 if(isset($_POST['move_user_to'])){
1186 $destination_dep = $_POST['move_user_to'];
1187 }else{
1188 msg_dialog::display(_("LDAP error"), _("Cannot move users to the requested department!"), ERROR_DIALOG);
1189 return(false);
1190 }
1192 foreach($this->outside_users as $b_dn => $data){
1193 $this->outside_users[$b_dn]['ldif'] ="";
1194 if($data['selected']){
1195 $dn = base64_decode($b_dn);
1196 $d_dn = preg_replace("/,.*$/",",".base64_decode($destination_dep),$dn);
1197 if(!$perform){
1198 $this->outside_users[$b_dn]['ldif'] = _("User will be moved from").":<br>\t".($ldap->fix($dn))."<br>"._("to").":<br>\t".($ldap->fix($d_dn));
1200 /* Check if there are references to this object */
1201 $ldap->search("(&(member=".LDAP::prepare4filter($dn).")(|(objectClass=gosaGroupOfNames)(objectClass=groupOfNames)))",array('dn'));
1202 $refs = "";
1203 while($attrs = $ldap->fetch()){
1204 $ref_dn = $attrs['dn'];
1205 $refs .= "<br />\t".$ref_dn;
1206 }
1207 if(!empty($refs)){
1208 $this->outside_users[$b_dn]['ldif'] .= "<br /><br /><i>"._("The following references will be updated").":</i>".$refs;
1209 }
1211 }else{
1212 $this->move($dn,$d_dn);
1213 }
1214 }
1215 }
1216 }
1219 function execute()
1220 {
1221 /* Initialise checks if this is the first call */
1222 if(!$this->checks_initialised || isset($_POST['reload'])){
1223 $this->initialize_checks();
1224 $this->checks_initialised = TRUE;
1225 }
1227 /*************
1228 * Winstations outside the group ou
1229 *************/
1231 if(isset($_POST['outside_winstations_dialog_cancel'])){
1232 $this->outside_winstations_dialog = FALSE;
1233 $this->dialog = FALSE;
1234 $this->show_details = FALSE;
1235 }
1237 if(isset($_POST['outside_winstations_dialog_whats_done'])){
1238 $this->migrate_outside_winstations(FALSE);
1239 }
1241 if(isset($_POST['outside_winstations_dialog_perform'])){
1242 $this->migrate_outside_winstations(TRUE);
1243 $this->search_outside_winstations();
1244 $this->dialog = FALSE;
1245 $this->show_details = FALSE;
1246 $this->outside_winstations_dialog = FALSE;
1247 }
1249 if(isset($_POST['outside_winstations_dialog'])){
1250 $this->outside_winstations_dialog = TRUE;
1251 $this->dialog = TRUE;
1252 }
1254 if($this->outside_winstations_dialog){
1256 /* Fix displayed dn syntax */
1257 $tmp = $this->outside_winstations;
1258 foreach($tmp as $key => $data){
1259 $tmp[$key]['dn'] = @LDAP::fix($data['dn']);
1260 }
1262 $smarty = get_smarty();
1263 $smarty->assign("ous",$this->get_all_winstation_ous());
1264 $smarty->assign("method","outside_winstations");
1265 $smarty->assign("outside_winstations",$tmp);
1266 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1267 }
1268 /*************
1269 * Groups outside the group ou
1270 *************/
1272 if(isset($_POST['outside_groups_dialog_cancel'])){
1273 $this->outside_groups_dialog = FALSE;
1274 $this->show_details = FALSE;
1275 $this->dialog = FALSE;
1276 }
1278 if(isset($_POST['outside_groups_dialog_whats_done'])){
1279 $this->show_details= TRUE;
1280 $this->migrate_outside_groups(FALSE);
1281 }
1283 if(isset($_POST['outside_groups_dialog_refresh'])){
1284 $this->show_details= FALSE;
1285 }
1287 if(isset($_POST['outside_groups_dialog_perform'])){
1288 $this->migrate_outside_groups(TRUE);
1289 $this->dialog = FALSE;
1290 $this->show_details = FALSE;
1291 $this->outside_groups_dialog = FALSE;
1292 $this->initialize_checks();
1293 }
1295 if(isset($_POST['outside_groups_dialog'])){
1296 $this->outside_groups_dialog = TRUE;
1297 $this->dialog = TRUE;
1298 }
1300 if($this->outside_groups_dialog){
1302 /* Fix displayed dn syntax */
1303 $tmp = $this->outside_groups;
1304 foreach($tmp as $key => $data){
1305 $tmp[$key]['dn'] = @LDAP::fix($data['dn']);
1306 }
1308 $smarty = get_smarty();
1309 $smarty->assign("ous",$this->get_all_group_ous());
1310 $smarty->assign("method","outside_groups");
1311 $smarty->assign("outside_groups",$tmp);
1312 $smarty->assign("group_details", $this->show_details);
1313 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1314 }
1316 /*************
1317 * User outside the people ou
1318 *************/
1320 if(isset($_POST['outside_users_dialog_cancel'])){
1321 $this->outside_users_dialog = FALSE;
1322 $this->dialog = FALSE;
1323 $this->show_details = FALSE;
1324 }
1326 if(isset($_POST['outside_users_dialog_whats_done'])){
1327 $this->show_details= TRUE;
1328 $this->migrate_outside_users(FALSE);
1329 }
1331 if(isset($_POST['outside_users_dialog_perform'])){
1332 $this->migrate_outside_users(TRUE);
1333 $this->initialize_checks();
1334 $this->dialog = FALSE;
1335 $this->show_details = FALSE;
1336 $this->outside_users_dialog = FALSE;
1337 }
1339 if (isset($_POST['outside_users_dialog_refresh'])){
1340 $this->show_details= FALSE;
1341 }
1343 if(isset($_POST['outside_users_dialog'])){
1344 $this->outside_users_dialog = TRUE;
1345 $this->dialog = TRUE;
1346 }
1348 if($this->outside_users_dialog){
1350 /* Fix displayed dn syntax */
1351 $tmp = $this->outside_users;
1352 foreach($tmp as $key => $data){
1353 $tmp[$key]['dn'] = @LDAP::fix($data['dn']);
1354 }
1356 $smarty = get_smarty();
1357 $smarty->assign("ous",$this->get_all_people_ous());
1358 $smarty->assign("method","outside_users");
1359 $smarty->assign("outside_users",$tmp);
1360 $smarty->assign("user_details", $this->show_details);
1361 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1362 }
1364 /*************
1365 * Root object check
1366 *************/
1368 if(isset($_POST['retry_root_create'])){
1370 $state = $this->checks['root']['STATUS'];
1371 $this->checkBase(FALSE);
1372 if($state != $this->checks['root']['STATUS']){
1373 $this->initialize_checks();
1374 }
1375 }
1377 /*************
1378 * User Migration handling
1379 *************/
1381 if(isset($_POST['retry_acls'])){
1382 $this->check_administrativeAccount();
1383 }
1385 if(isset($_POST['create_acls'])){
1386 $this->acl_create_dialog = TRUE;
1387 $this->dialog = TRUE;
1388 }
1390 if(isset($_POST['create_acls_cancel'])){
1391 $this->acl_create_dialog = FALSE;
1392 $this->dialog = FALSE;
1393 $this->show_details = FALSE;
1394 }
1396 # if(isset($_POST['create_acls_create_confirmed'])){
1397 # if($this->create_admin()){
1398 # $this->acl_create_dialog = FALSE;
1399 # $this->dialog = FALSE;
1400 # $this->show_details = FALSE;
1401 # $this->initialize_checks();
1402 # }
1403 # }
1405 if(isset($_POST['create_acls_create'])){
1406 $this->create_admin(TRUE);
1407 }
1409 if(isset($_POST['create_admin_user'])){
1410 if($this->create_admin_user()){
1411 $this->dialog = FALSE;
1412 $this->show_details = FALSE;
1413 }
1414 }
1416 if($this->acl_create_dialog){
1417 $smarty = get_smarty();
1419 $uid = "admin";
1420 if(isset($_POST['new_user_uid'])){
1421 $uid = $_POST['new_user_uid'];
1422 }
1424 $smarty->assign("new_user_uid",$uid);
1425 $smarty->assign("new_user_password",@$_POST['new_user_password']);
1426 $smarty->assign("new_user_password2",@$_POST['new_user_password2']);
1427 $smarty->assign("method","create_acls");
1428 $smarty->assign("acl_create_selected",$this->acl_create_selected);
1429 $smarty->assign("what_will_be_done_now",$this->acl_create_changes);
1430 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1431 }
1433 /*************
1434 * User Migration handling
1435 *************/
1437 /* Refresh list of deparments */
1438 if(isset($_POST['users_visible_migrate_refresh'])){
1439 $this->check_gosaAccounts();
1440 }
1442 /* Open migration dialog */
1443 if(isset($_POST['users_visible_migrate'])){
1444 $this->show_details= FALSE;
1445 $this->users_migration_dialog = TRUE;
1446 $this->dialog =TRUE;
1447 }
1449 /* Close migration dialog */
1450 if(isset($_POST['users_visible_migrate_close'])){
1451 $this->users_migration_dialog = FALSE;
1452 $this->dialog =FALSE;
1453 $this->show_details = FALSE;
1454 }
1456 /* Start migration */
1457 if(isset($_POST['users_visible_migrate_migrate'])){
1458 if($this->migrate_gosaAccounts()){
1459 $this->initialize_checks();
1460 $this->dialog = FALSE;
1461 $this->show_details = FALSE;
1462 $this->users_migration_dialog = FALSE;
1463 }
1464 }
1466 /* Start migration */
1467 if(isset($_POST['users_visible_migrate_whatsdone'])){
1468 $this->migrate_gosaAccounts(TRUE);
1469 }
1471 /* Display migration dialog */
1472 if($this->users_migration_dialog){
1474 /* Fix displayed dn syntax */
1475 $tmp = $this->users_to_migrate;
1476 foreach($tmp as $key => $data){
1477 $tmp[$key]['dn'] = @LDAP::fix($data['dn']);
1478 }
1480 $smarty = get_smarty();
1481 $smarty->assign("users_to_migrate",$tmp);
1482 $smarty->assign("method","migrate_users");
1483 $smarty->assign("user_details", $this->show_details);
1484 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1485 }
1488 /*************
1489 * Department Migration handling
1490 *************/
1492 /* Refresh list of deparments */
1493 if(isset($_POST['deps_visible_migrate_refresh'])){
1494 $this->check_organizationalUnits();
1495 $this->show_details= FALSE;
1496 }
1498 /* Open migration dialog */
1499 if(isset($_POST['deps_visible_migrate'])){
1500 $this->dep_migration_dialog = TRUE;
1501 $this->dialog =TRUE;
1502 }
1504 /* Close migration dialog */
1505 if(isset($_POST['deps_visible_migrate_close'])){
1506 $this->dep_migration_dialog = FALSE;
1507 $this->dialog =FALSE;
1508 $this->show_details = FALSE;
1509 }
1511 /* Start migration */
1512 if(isset($_POST['deps_visible_migrate_migrate'])){
1513 if($this->migrate_organizationalUnits()){
1514 $this->show_details= FALSE;
1515 $this->check_organizationalUnits();
1516 $this->dialog = FALSE;
1517 $this->dep_migration_dialog = FALSE;
1518 }
1519 }
1521 /* Start migration */
1522 if(isset($_POST['deps_visible_migrate_whatsdone'])){
1523 $this->migrate_organizationalUnits(TRUE);
1524 }
1526 /* Display migration dialog */
1527 if($this->dep_migration_dialog){
1528 $smarty = get_smarty();
1530 /* Fix displayed dn syntax */
1531 $tmp = $this->deps_to_migrate;
1532 foreach($tmp as $key => $data){
1533 $tmp[$key]['dn'] = @LDAP::fix($data['dn']);
1534 }
1536 $smarty->assign("deps_to_migrate",$tmp);
1537 $smarty->assign("method","migrate_deps");
1538 $smarty->assign("deps_details", $this->show_details);
1539 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1540 }
1542 $smarty = get_smarty();
1543 $smarty->assign("checks",$this->checks);
1544 $smarty->assign("method","default");
1545 return($smarty->fetch(get_template_path("setup_migrate.tpl",TRUE,dirname(__FILE__))));
1546 }
1549 function save_object()
1550 {
1551 $this->is_completed= TRUE;
1553 /* Capture all selected winstations from outside_winstations_dialog */
1554 if($this->outside_winstations_dialog){
1555 foreach($this->outside_winstations as $dn => $data){
1556 if(isset($_POST['select_winstation_'.$dn])){
1557 $this->outside_winstations[$dn]['selected'] = TRUE;
1558 }else{
1559 $this->outside_winstations[$dn]['selected'] = FALSE;
1560 }
1561 }
1562 }
1564 /* Capture all selected groups from outside_groups_dialog */
1565 if($this->outside_groups_dialog){
1566 foreach($this->outside_groups as $dn => $data){
1567 if(isset($_POST['select_group_'.$dn])){
1568 $this->outside_groups[$dn]['selected'] = TRUE;
1569 }else{
1570 $this->outside_groups[$dn]['selected'] = FALSE;
1571 }
1572 }
1573 }
1575 /* Capture all selected users from outside_users_dialog */
1576 if($this->outside_users_dialog){
1577 foreach($this->outside_users as $dn => $data){
1578 if(isset($_POST['select_user_'.$dn])){
1579 $this->outside_users[$dn]['selected'] = TRUE;
1580 }else{
1581 $this->outside_users[$dn]['selected'] = FALSE;
1582 }
1583 }
1584 }
1586 /* Get "create acl" dialog posts */
1587 if($this->acl_create_dialog){
1589 if(isset($_POST['create_acls_create_abort'])){
1590 $this->acl_create_selected = "";
1591 }
1592 }
1594 /* Get selected departments */
1595 if($this->dep_migration_dialog){
1596 foreach($this->deps_to_migrate as $id => $data){
1597 if(isset($_POST['migrate_'.$id])){
1598 $this->deps_to_migrate[$id]['checked'] = TRUE;
1599 }else{
1600 $this->deps_to_migrate[$id]['checked'] = FALSE;
1601 }
1602 }
1603 }
1605 /* Get selected users */
1606 if($this->users_migration_dialog){
1607 foreach($this->users_to_migrate as $id => $data){
1608 if(isset($_POST['migrate_'.$id])){
1609 $this->users_to_migrate[$id]['checked'] = TRUE;
1610 }else{
1611 $this->users_to_migrate[$id]['checked'] = FALSE;
1612 }
1613 }
1614 }
1615 }
1618 /* Check if the root object exists.
1619 * If the parameter just_check is true, then just check if the
1620 * root object is missing and update the info messages.
1621 * If the Parameter is false, try to create a new root object.
1622 */
1623 function checkBase($just_check = TRUE)
1624 {
1625 /* Establish ldap connection */
1626 $cv = $this->parent->captured_values;
1627 $ldap_l = new LDAP($cv['admin'],
1628 $cv['password'],
1629 $cv['connection'],
1630 FALSE,
1631 $cv['tls']);
1633 $ldap = new ldapMultiplexer($ldap_l);
1635 /* Check if root object exists */
1636 $ldap->cd($cv['base']);
1637 $ldap->set_size_limit(1);
1638 $res = $ldap->search("(objectClass=*)");
1639 $ldap->set_size_limit(0);
1640 $err = ldap_errno($ldap->cid);
1642 if( !$res ||
1643 $err == 0x20 || # LDAP_NO_SUCH_OBJECT
1644 $err == 0x40) { # LDAP_NAMING_VIOLATION
1646 /* Root object doesn't exists
1647 */
1648 if($just_check){
1649 $this->checks['root']['STATUS'] = FALSE;
1650 $this->checks['root']['STATUS_MSG']= _("Failed");
1651 $this->checks['root']['ERROR_MSG'] = _("The LDAP root object is missing. It is required to use your LDAP service.").' ';
1652 $this->checks['root']['ERROR_MSG'].= "<input type='submit' name='retry_root_create' value='"._("Try to create root object")."'>";
1653 return(FALSE);
1654 }else{
1656 /* Add root object */
1657 $ldap->cd($cv['base']);
1658 $res = $ldap->create_missing_trees($cv['base']);
1660 /* If adding failed, tell the user */
1661 if(!$res){
1662 $this->checks['root']['STATUS'] = FALSE;
1663 $this->checks['root']['STATUS_MSG']= _("Failed");
1664 $this->checks['root']['ERROR_MSG'] = _("Root object couldn't be created, you should try it on your own.");
1665 $this->checks['root']['ERROR_MSG'].= " <input type='submit' name='retry_root_create' value='"._("Try to create root object")."'>";
1666 return($res);;
1667 }
1668 }
1669 }
1671 /* Create & remove of dummy object was successful */
1672 $this->checks['root']['STATUS'] = TRUE;
1673 $this->checks['root']['STATUS_MSG']= _("Ok");
1674 }
1677 /* Return ldif information for a
1678 * given attribute array
1679 */
1680 function array_to_ldif($atts)
1681 {
1682 $ret = "";
1683 unset($atts['count']);
1684 unset($atts['dn']);
1685 foreach($atts as $name => $value){
1686 if(is_numeric($name)) {
1687 continue;
1688 }
1689 if(is_array($value)){
1690 unset($value['count']);
1691 foreach($value as $a_val){
1692 $ret .= $name.": ". $a_val."\n";
1693 }
1694 }else{
1695 $ret .= $name.": ". $value."\n";
1696 }
1697 }
1698 return(preg_replace("/\n$/","",$ret));
1699 }
1702 function get_user_list()
1703 {
1704 /* Establish ldap connection */
1705 $cv = $this->parent->captured_values;
1706 $ldap_l = new LDAP($cv['admin'],
1707 $cv['password'],
1708 $cv['connection'],
1709 FALSE,
1710 $cv['tls']);
1712 $ldap = new ldapMultiplexer($ldap_l);
1713 $ldap->cd($cv['base']);
1714 $ldap->search("(objectClass=gosaAccount)",array("dn"));
1716 $tmp = array();
1717 while($attrs = $ldap->fetch()){
1718 $tmp[base64_encode($attrs['dn'])] = @LDAP::fix($attrs['dn']);
1719 }
1720 return($tmp);
1721 }
1724 function get_all_people_ous()
1725 {
1726 /* Get collected configuration settings */
1727 $cv = $this->parent->captured_values;
1728 $people_ou = trim($cv['peopleou']);
1730 /* Establish ldap connection */
1731 $cv = $this->parent->captured_values;
1732 $ldap_l = new LDAP($cv['admin'],
1733 $cv['password'],
1734 $cv['connection'],
1735 FALSE,
1736 $cv['tls']);
1738 $ldap = new ldapMultiplexer($ldap_l);
1740 /*****************
1741 * If people ou is NOT empty
1742 * search for for all objects matching the given container
1743 *****************/
1744 if(!empty($people_ou)){
1745 $ldap->search("(".$people_ou.")",array("dn"));
1747 /* Create people ou if there is currently none */
1748 if($ldap->count() == 0 ){
1749 $add_dn = $cv['peopleou'].",".$cv['base'];
1750 $naming_attr = preg_replace("/=.*$/","",$add_dn);
1751 $naming_value = preg_replace("/^[^=]*+=([^,]*).*$/","\\1",$add_dn);
1752 $add = array();
1753 $add['objectClass'] = array("organizationalUnit");
1754 $add[$naming_attr] = $naming_value;
1755 $ldap->cd($cv['base']);
1756 $ldap->create_missing_trees(preg_replace("/^[^,]+,/","",$add_dn));
1757 $ldap->cd($add_dn);
1758 $ldap->add($add);
1759 }
1761 /* Create result */
1762 $ldap->search("(".$cv['peopleou'].")",array("dn"));
1763 $tmp = array();
1764 while($attrs= $ldap->fetch()){
1765 if(!preg_match("/ou=snapshots,/",$attrs['dn'])){
1766 $tmp[base64_encode($attrs['dn'])] = $ldap->fix($attrs['dn']);
1767 }
1768 }
1769 } else{
1771 /************
1772 * If people ou is empty
1773 * Get all valid gosaDepartments
1774 ************/
1775 $ldap->cd($cv['base']);
1776 $tmp = array();
1777 $ldap->search("(&(objectClass=gosaDepartment)(ou=*))",array("dn"));
1778 $tmp[base64_encode($cv['base'])] = $ldap->fix($cv['base']);
1779 while($attrs = $ldap->fetch()){
1780 $tmp[base64_encode($attrs['dn'])] = $ldap->fix($attrs['dn']);;
1781 }
1782 }
1783 return($tmp);
1784 }
1787 function get_all_winstation_ous()
1788 {
1789 /* Establish ldap connection */
1790 $cv = $this->parent->captured_values;
1791 $ldap_l = new LDAP($cv['admin'],
1792 $cv['password'],
1793 $cv['connection'],
1794 FALSE,
1795 $cv['tls']);
1797 $ldap = new ldapMultiplexer($ldap_l);
1799 /* Get winstation ou */
1800 if($cv['generic_settings']['wws_ou_active']) {
1801 $winstation_ou = $cv['generic_settings']['ws_ou'];
1802 }else{
1803 $winstation_ou = "ou=winstations";
1804 }
1806 $ldap->cd($cv['base']);
1807 $ldap->search("(".$winstation_ou.")",array("dn"));
1809 if($ldap->count() == 0 ){
1810 $add_dn = $winstation_ou.",ou=systems,".$cv['base'];
1811 $naming_attr = preg_replace("/=.*$/","",$add_dn);
1812 $naming_value = preg_replace("/^[^=]*+=([^,]*).*$/","\\1",$add_dn);
1813 $add = array();
1814 $add['objectClass'] = array("organizationalUnit");
1815 $add[$naming_attr] = $naming_value;
1817 $ldap->cd($cv['base']);
1818 $ldap->create_missing_trees(preg_replace("/^[^,]+,/","",$add_dn));
1819 $ldap->cd($add_dn);
1820 $ldap->add($add);
1821 }
1823 $ldap->search("(".$winstation_ou.")",array("dn"));
1824 $tmp = array();
1825 while($attrs= $ldap->fetch()){
1826 if(!preg_match("/ou=snapshots,/",$attrs['dn'])){
1827 $tmp[base64_encode($attrs['dn'])] = $ldap->fix($attrs['dn']);
1828 }
1829 }
1830 return($tmp);
1831 }
1834 function get_all_group_ous()
1835 {
1836 /* Establish ldap connection */
1837 $cv = $this->parent->captured_values;
1838 $ldap_l = new LDAP($cv['admin'],
1839 $cv['password'],
1840 $cv['connection'],
1841 FALSE,
1842 $cv['tls']);
1844 $ldap = new ldapMultiplexer($ldap_l);
1846 $group_ou = trim($cv['groupou']);
1847 if(!empty($group_ou)){
1848 $group_ou = trim($group_ou);
1849 }
1851 /************
1852 * If group ou is NOT empty
1853 * Get all valid group ous, create one if necessary
1854 ************/
1855 $ldap->cd($cv['base']);
1856 if(!empty($group_ou)){
1857 $ldap->search("(".$group_ou.")",array("dn"));
1858 if($ldap->count() == 0 ){
1859 $add_dn = $group_ou.$cv['base'];
1860 $naming_attr = preg_replace("/=.*$/","",$add_dn);
1861 $naming_value = preg_replace("/^[^=]*+=([^,]*).*$/","\\1",$add_dn);
1862 $add = array();
1863 $add['objectClass'] = array("organizationalUnit");
1864 $add[$naming_attr] = $naming_value;
1866 $ldap->cd($cv['base']);
1867 $ldap->create_missing_trees(preg_replace("/^[^,]+,/","",$add_dn));
1868 $ldap->cd($add_dn);
1869 $ldap->add($add);
1870 }
1871 $ldap->search("(".$group_ou.")",array("dn"));
1872 $tmp = array();
1873 while($attrs= $ldap->fetch()){
1874 if(!preg_match("/ou=snapshots,/",$attrs['dn'])){
1875 $tmp[base64_encode($attrs['dn'])] = $ldap->fix($attrs['dn']);
1876 }
1877 }
1878 }else{
1879 /************
1880 * If group ou is empty
1881 * Get all valid gosaDepartments
1882 ************/
1883 $ldap->cd($cv['base']);
1884 $tmp = array();
1885 $ldap->search("(&(objectClass=gosaDepartment)(ou=*))",array("dn"));
1886 $tmp[base64_encode($cv['base'])] = $ldap->fix($cv['base']);
1887 while($attrs = $ldap->fetch()){
1888 $tmp[base64_encode($attrs['dn'])] = $ldap->fix($attrs['dn']);;
1889 }
1890 }
1891 return($tmp);
1892 }
1895 function get_group_list()
1896 {
1897 /* Establish ldap connection */
1898 $cv = $this->parent->captured_values;
1899 $ldap_l = new LDAP($cv['admin'],
1900 $cv['password'],
1901 $cv['connection'],
1902 FALSE,
1903 $cv['tls']);
1905 $ldap = new ldapMultiplexer($ldap_l);
1907 $ldap->cd($cv['base']);
1908 $ldap->search("(objectClass=posixGroup)",array("dn"));
1910 $tmp = array();
1911 while($attrs = $ldap->fetch()){
1912 $tmp[base64_encode($attrs['dn'])] = @LDAP::fix($attrs['dn']);
1913 }
1914 return($tmp);
1915 }
1918 function move($source,$destination)
1919 {
1920 /* Establish ldap connection */
1921 $cv = $this->parent->captured_values;
1922 $ldap_l = new LDAP($cv['admin'],
1923 $cv['password'],
1924 $cv['connection'],
1925 FALSE,
1926 $cv['tls']);
1928 $ldap = new ldapMultiplexer($ldap_l);
1930 /* Update object references in gosaGroupOfNames */
1931 $ogs_to_fix = array();
1932 $ldap->cd($cv['base']);
1933 $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($source).'))', array('cn','member'));
1934 while ($attrs= $ldap->fetch()){
1935 $dn = $attrs['dn'];
1936 $attrs = $this->cleanup_array($attrs);
1937 $member_new = array($destination);
1938 foreach($attrs['member'] as $member){
1939 if($member != $source){
1940 $member_new[] = $member;
1941 }
1942 }
1943 $attrs['member'] = $member_new;
1944 $ogs_to_fix[$dn] = $attrs;
1945 }
1947 /* Copy source to destination dn */
1948 $ldap->cat($source);
1949 $new_data = $this->cleanup_array($ldap->fetch());
1950 $ldap->cd($destination);
1951 $res = $ldap->add($new_data);
1953 /* Display warning if copy failed */
1954 if(!$res){
1955 msg_dialog::display(_("LDAP error"), sprintf(_("Copy '%s' to '%s' failed:")."<br><br><i>%s</i>", LDAP::fix($source), LDAP::fix($destination), $ldap->get_error()), ERROR_DIALOG);
1956 }else{
1957 $res = $ldap->rmDir($source);
1958 if (!$ldap->success()){
1959 msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $source, LDAP_DEL, get_class()));
1960 }
1962 /* Object is copied, so update its references */
1963 foreach($ogs_to_fix as $dn => $data){
1964 $ldap->cd($dn);
1965 $ldap->modify($data);
1966 }
1967 }
1968 }
1971 /* Cleanup ldap result to be able to write it be to ldap */
1972 function cleanup_array($attrs)
1973 {
1974 foreach($attrs as $key => $value) {
1975 if(is_numeric($key) || in_array($key,array("count","dn"))){
1976 unset($attrs[$key]);
1977 }
1978 if(is_array($value) && isset($value['count'])){
1979 unset($attrs[$key]['count']);
1980 }
1981 }
1982 return($attrs);
1983 }
1984 }
1986 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1987 ?>