class_setupStep_Migrate.inc 44.39 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2007  Fabian Hickert
  Copyright (C) 2011-2015  FusionDirectory
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
/****************
 * FUNCTIONS
Step_Migrate                - Constructor.
update_strings              - Used to update the displayed step informations.
initialize_checks           - Initialize migration steps.
check_ldap_permissions      - Check if the used admin account has full access to the ldap database.
check_gosaAccounts          - Check if there are users without the required objectClasses.
migrate_gosaAccounts        - Migrate selected users to FusionDirectory user accounts.
check_orgUnits   - Check if there are departments, that are not visible for FusionDirectory
migrate_orgUnits - Migrate selected departments
check_adminAccount - Check if there is at least one acl entry available
checkBase                   - Check if there is a root object available
get_user_list               - Get list of available users
create_admin
create_admin_user
execute                     - Generate html output of this plugin
save_object                 - Save posts
array_to_ldif               - Create ldif output of an ldap result array
 ****************/
class CheckFailedException extends Exception
  private $error;
  public function __construct($msg, $error)
    parent::__construct($msg);
    $this->error = $error;
  public function getError()
    return $this->error;
class StepMigrateDialog extends GenericDialog
  protected $post_cancel = 'dialog_cancel';
  protected $post_finish = 'dialog_confirm';
  private $infos;
  private $tplfile;
  private $check;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
public function __construct(&$check, $tpl, $infos) { $this->attribute = NULL; $this->dialog = NULL; $this->infos = $infos; $this->tplfile = $tpl; $this->check = $check; } public function dialog_execute() { if ( isset($_POST['dialog_showchanges']) || isset($_POST['dialog_hidechanges']) || isset($_POST['dialog_refresh'])) { $this->infos = $this->check->dialog_refresh(); } $smarty = get_smarty(); $smarty->assign('infos', $this->infos); return $smarty->fetch(get_template_path($this->tplfile, TRUE, dirname(__FILE__))); } function handle_finish () { if ($this->check->migrate_confirm()) { return FALSE; } else { return $this->dialog_execute(); } } function handle_cancel () { return FALSE; } } class StepMigrateCheck { public $name; public $title; public $status = FALSE; public $msg = ''; public $error = ''; public $fnc; private $step; public function __construct($step, $name, $title) { $this->name = $name; $this->title = $title; $this->fnc = 'check_'.$name; $this->step = $step; } public function run($fnc = NULL) { if ($fnc === NULL) { $fnc = $this->fnc; } try { $this->msg = _('Ok'); $this->error = $this->step->$fnc($this); $this->status = TRUE; } catch (CheckFailedException $e) { $this->status = FALSE; $this->msg = $e->getMessage(); $this->error = $e->getError(); }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
} public function save_object() { if (isset($_POST[$this->name.'_create'])) { $fnc = $this->fnc.'_create'; $this->step->$fnc($this); } elseif (isset($_POST[$this->name.'_migrate'])) { $fnc = $this->fnc.'_migrate'; $this->step->$fnc($this); } } public function submit ($value = NULL, $id = 'migrate') { if ($value === NULL) { $value = _('Migrate'); } return '<input type="submit" name="'.$this->name.'_'.$id.'" value="'.$value.'"/>'; } public function migrate_confirm() { $fnc = $this->fnc.'_migrate'.'_confirm'; $res = $this->step->$fnc($this); if ($res) { $this->run(); } return $res; } public function dialog_refresh() { $fnc = $this->fnc.'_migrate'.'_refresh'; return $this->step->$fnc($this); } } class Step_Migrate extends setupStep { var $header_image = "geticon.php?context=applications&icon=utilities-system-monitor&size=48"; /* Root object classes */ var $rootOC_details = array(); /* Entries needing migration */ var $orgUnits_toMigrate = array(); var $gosaAccounts_toMigrate = array(); var $outsideUsers_toMigrate = array(); var $outsideGroups_toMigrate = array(); /* check for multiple use of same uidNumber */ var $check_uidNumbers = array(); /* check for multiple use of same gidNumber */ var $check_gidNumbers = array(); /* Defaults ACL roles */ var $defaultRoles; static function getAttributesInfo() { return array( 'checks' => array( 'class' => array('fullwidth'), 'name' => _('PHP module and extension checks'), 'template' => get_template_path("setup_migrate.tpl", TRUE, dirname(__FILE__)), 'attrs' => array( new FakeAttribute('checks') )
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
), ); } function __construct() { parent::__construct(); $this->fill_defaultRoles(); } function update_strings() { $this->s_title = _("LDAP inspection"); $this->s_title_long = _("LDAP inspection"); $this->s_info = _("Analyze your current LDAP for FusionDirectory compatibility"); } function fill_defaultRoles() { $this->defaultRoles = array( array( 'cn' => 'manager', 'description' => _('Give all rights on users in the given branch'), 'objectclass' => array('top', 'gosaRole'), 'gosaAclTemplate' => '0:user/password;cmdrw,user/user;cmdrw,user/posixAccount;cmdrw' ), array( 'cn' => 'editowninfos', 'description' => _('Allow users to edit their own information (main tab and posix use only on base)'), 'objectclass' => array('top', 'gosaRole'), 'gosaAclTemplate' => '0:user/posixAccount;srw,user/user;srw' ), array( 'cn' => 'editowninfos', 'description' => _('Allow users to edit their own password (use only on base)'), 'objectclass' => array('top', 'gosaRole'), 'gosaAclTemplate' => '0:user/password;srw' ), ); } function initialize_checks() { global $config; $config->get_departments(); $checks = array( 'baseOC' => new StepMigrateCheck($this, 'baseOC', _('Inspecting object classes in root object')), 'permissions' => new StepMigrateCheck($this, 'permissions', _('Checking permission for LDAP database')), 'gosaAccounts' => new StepMigrateCheck($this, 'gosaAccounts', _('Checking for invisible users')), 'adminAccount' => new StepMigrateCheck($this, 'adminAccount', _('Checking for super administrator')), 'defaultACLs' => new StepMigrateCheck($this, 'defaultACLs', _('Checking for default ACL roles and groups')), 'outsideUsers' => new StepMigrateCheck($this, 'outsideUsers', _('Checking for users outside the people tree')), 'outsideGroups' => new StepMigrateCheck($this, 'outsideGroups', _('Checking for groups outside the groups tree')), 'orgUnits' => new StepMigrateCheck($this, 'orgUnits', _('Checking for invisible departments')), 'uidNumber' => new StepMigrateCheck($this, 'uidNumber', _('Checking for duplicated UID numbers')), 'gidNumber' => new StepMigrateCheck($this, 'gidNumber', _('Checking for duplicate GID numbers')), ); $this->checks = $checks; } /* Return ldif information for a given attribute array */ function array_to_ldif($attrs) { $ret = ''; unset($attrs['count']); unset($attrs['dn']); foreach ($attrs as $name => $value) { if (is_numeric($name)) {
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
continue; } if (is_array($value)) { unset($value['count']); foreach ($value as $a_val) { $ret .= $name.': '. $a_val."\n"; } } else { $ret .= $name.': '. $value."\n"; } } return preg_replace("/\n$/", '', $ret); } function execute() { if (empty($this->checks) || isset($_POST['reload'])) { $this->initialize_checks(); foreach ($this->checks as $check) { $check->run(); } } return parent::execute(); } function save_object() { $this->is_completed = TRUE; parent::save_object(); foreach ($this->checks as $check) { $check->save_object(); } } /* Check if the root object includes the required object classes, e.g. gosaDepartment is required for ACLs. * If the parameter just_check is TRUE, then just check for the OCs. * If the Parameter is FALSE, try to add the required object classes. */ function check_baseOC(&$checkobj) { global $config; $ldap = $config->get_ldap_link(); /* Check if root object exists */ $ldap->cd($config->current['BASE']); $ldap->cat($config->current['BASE']); if (!$ldap->count()) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); } $attrs = $ldap->fetch(); /* Root object doesn't exists */ if (!in_array("gosaDepartment", $attrs['objectClass'])) { $this->rootOC_details = array(); $mods = array(); /* Get list of possible container objects, to be able to detect naming * attributes and missing attribute types. */ if (!class_available("departmentManagement")) { throw new CheckFailedException( _("Failed"), sprintf(_("Missing FusionDirectory object class '%s'!"), "departmentManagement"). "&nbsp;"._("Please check your installation.") ); }
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
/* Try to detect base class type, e.g. is it a dcObject */ $dep_types = departmentManagement::getDepartmentTypes(); $dep_type = ""; $attrs['objectClass'][] = 'gosaDepartment'; // This allow us to filter it as if it was already migrated foreach ($dep_types as $type) { if (objects::isOfType($attrs, $type)) { $dep_type = $type; break; } } $key = array_search('gosaDepartment', $attrs['objectClass']); unset($attrs['objectClass'][$key]); /* If no known base class was detect, abort with message */ if (empty($dep_type)) { throw new CheckFailedException( _("Failed"), sprintf(_("Cannot handle the structural object type of your root object. Please try to add the object class '%s' manually."), "gosaDepartment") ); } $dep_infos = objects::infos($dep_type); /* Create 'current' and 'target' object properties, to be able to display * a set of modifications required to create a valid FusionDirectory department. */ $str = "dn: ".$config->current['BASE']."\n"; for ($i = 0; $i < $attrs['objectClass']['count']; $i++) { $str .= "objectClass: ".$attrs['objectClass'][$i]."\n"; } $this->rootOC_details['current'] = $str; /* Create target infos */ $str = "dn: ".$config->current['BASE']."\n"; for ($i = 0; $i < $attrs['objectClass']['count']; $i++) { $str .= "objectClass: ".$attrs['objectClass'][$i]."\n"; $mods['objectClass'][] = $attrs['objectClass'][$i]; } $mods['objectClass'][] = "gosaDepartment"; $str .= "<b>objectClass: gosaDepartment</b>\n"; /* Append attribute 'ou', it is required by gosaDepartment */ if (!isset($attrs['ou'])) { $val = "GOsa"; if (isset($attrs[$dep_infos['mainAttr']][0])) { $val = $attrs[$dep_infos['mainAttr']][0]; } $str .= "<b>ou: ".$val."</b>\n"; $mods['ou'] = $val; } /*Append description, it is required by gosaDepartment too */ if (!isset($attrs['description'])) { $val = "GOsa"; if (isset($attrs[$dep_infos['mainAttr']][0])) { $val = $attrs[$dep_infos['mainAttr']][0]; } $str .= "<b>description: ".$val."</b>\n"; $mods['description'] = $val; } $this->rootOC_details['target'] = $str; $this->rootOC_details['mods'] = $mods; /* Add button that allows to open the migration details */ throw new CheckFailedException( _('Failed'), '&nbsp;'.$checkobj->submit()
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
); } /* Create & remove of dummy object was successful */ return ''; } function check_baseOC_migrate (&$checkobj) { $this->openDialog(new StepMigrateDialog($checkobj, 'setup_migrate_baseOC.tpl', $this->rootOC_details)); } function check_baseOC_migrate_confirm () { global $config; $ldap = $config->get_ldap_link(); /* Check if root object exists */ $ldap->cd($config->current['BASE']); $ldap->cat($config->current['BASE']); $attrs = $ldap->fetch(); /* Root object doesn't exists */ if (!in_array("gosaDepartment", $attrs['objectClass'])) { /* Add root object */ $ldap->cd($config->current['BASE']); if (isset($this->rootOC_details['mods'])) { $res = $ldap->modify($this->rootOC_details['mods']); if (!$res) { msg_dialog::display(_('LDAP error'), msgPool::ldaperror($ldap->get_error(), $config->current['BASE'], LDAP_MOD, get_class()), LDAP_ERROR); } $this->checks['adminAccount']->run(); return $res; } else { trigger_error('No modifications to make... '); } return TRUE; } return TRUE; } /* Check ldap accessibility * Create and remove a dummy object, * to ensure that we have the necessary permissions */ function check_permissions(&$checkobj) { global $config; $ldap = $config->get_ldap_link(); /* Create dummy entry */ $name = 'GOsa_setup_text_entry_'.session_id().rand(0, 999999); $dn = 'ou='.$name.','.$config->current['BASE']; $testEntry = array(); $testEntry['objectClass'][] = 'top'; $testEntry['objectClass'][] = 'organizationalUnit'; $testEntry['objectClass'][] = 'gosaDepartment'; $testEntry['description'] = 'Created by FusionDirectory setup, this object can be removed.'; $testEntry['ou'] = $name; /* check if simple ldap cat will be successful */ $res = $ldap->cat($config->current['BASE']); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); }
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
/* Try to create dummy object */ $ldap->cd ($dn); $res = $ldap->add($testEntry); $ldap->cat($dn); if (!$ldap->count()) { new log("view", "setup/".get_class($this), $dn, array(), $ldap->get_error()); throw new CheckFailedException( _('Failed'), sprintf(_('The specified user "%s" does not have full access to your LDAP database.'), $config->current['ADMINDN']) ); } /* Try to remove created entry */ $res = $ldap->rmDir($dn); $ldap->cat($dn); if ($ldap->count()) { new log("view", "setup/".get_class($this), $dn, array(), $ldap->get_error()); throw new CheckFailedException( _('Failed'), sprintf(_('The specified user "%s" does not have full access to your ldap database.'), $config->current['ADMINDN']) ); } /* Create & remove of dummy object was successful */ return ''; } /* Check if there are users which will * be invisible for FusionDirectory */ function check_gosaAccounts(&$checkobj) { global $config; $ldap = $config->get_ldap_link(); /* Remember old list of invisible users, to be able to set * the 'html checked' status for the checkboxes again */ $old = $this->gosaAccounts_toMigrate; $this->gosaAccounts_toMigrate = array(); /* Get all invisible users */ $ldap->cd($config->current['BASE']); $res = $ldap->search( '(&'. '(|'. '(objectClass=posixAccount)'. '(objectClass=person)'. '(objectClass=OpenLDAPperson)'. ')'. '(!(objectClass=inetOrgPerson))'. '(uid=*)'. ')', array('sn','givenName','cn','uid') ); while ($attrs = $ldap->fetch()) { if (!preg_match('/,dc=addressbook,/', $attrs['dn'])) { $attrs['checked'] = FALSE; $attrs['before'] = ""; $attrs['after'] = ""; /* Set objects to selected, that were selected before reload */ if (isset($old[base64_encode($attrs['dn'])])) { $attrs['checked'] = $old[base64_encode($attrs['dn'])]['checked']; } $this->gosaAccounts_toMigrate[base64_encode($attrs['dn'])] = $attrs; } }