class_setupStepMigrate.inc 45.82 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2007  Fabian Hickert
  Copyright (C) 2011-2019  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
setupStepMigrate                - Constructor.
update_strings              - Used to update the displayed step information.
initialize_checks           - Initialize migration steps.
check_ldap_permissions      - Check if the used admin account has full access to the ldap database.
check_accounts              - Check if there are users without the required objectClasses.
migrate_accounts            - 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
readPost                    - Save posts
update                      - Update state
render                      - Generate html output of this plugin
array_to_ldif               - Create ldif output of an ldap result array
 ****************/
class CheckFailedException extends FusionDirectoryException
  private $error;
  public function __construct ($msg, $error)
    parent::__construct($msg);
    $this->error = $error;
  public function getError ()
    return $this->error;
class StepMigrateDialog implements FusionDirectoryDialog
  protected $post_cancel = 'dialog_cancel';
  protected $post_finish = 'dialog_confirm';
  private $infos;
  private $tplfile;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
private $check; public function __construct (&$check, $tpl, $infos) { $this->infos = $infos; $this->tplfile = $tpl; $this->check = $check; } public function readPost () { if (isset($_POST[$this->post_cancel])) { $this->handleCancel(); } elseif (isset($_POST[$this->post_finish]) || isset($_GET[$this->post_finish])) { $this->handleFinish(); } elseif ( isset($_POST['dialog_showchanges']) || isset($_POST['dialog_hidechanges']) || isset($_POST['dialog_refresh'])) { $this->infos = $this->check->dialog_refresh(); } } public function update (): bool { return isset($this->check); } public function render (): string { $smarty = get_smarty(); $smarty->assign('infos', $this->infos); return $smarty->fetch(get_template_path($this->tplfile, TRUE, dirname(__FILE__))); } protected function handleFinish () { if ($this->check->migrate_confirm()) { unset($this->check); } } protected function handleCancel () { unset($this->check); } public function getInfos (): array { return $this->infos; } } class StepMigrateCheck { public $name; public $title; public $status = FALSE; public $msg = ''; public $error = ''; public $fnc; private $step; public function __construct (setupStepMigrate $step, string $name, string $title) { $this->name = $name; $this->title = $title; $this->fnc = 'check_'.$name; $this->step = $step; }
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
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(); } } public function readPost () { if (isset($_POST[$this->name.'_create'])) { $createFnc = $this->fnc.'_create'; $this->step->$createFnc($this); } elseif (isset($_POST[$this->name.'_migrate'])) { $migrateFnc = $this->fnc.'_migrate'; $this->step->$migrateFnc($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 () { $migrateConfirmFnc = $this->fnc.'_migrate'.'_confirm'; $res = $this->step->$migrateConfirmFnc($this); if ($res) { $this->run(); } return $res; } public function dialog_refresh () { $migrateRefreshFnc = $this->fnc.'_migrate'.'_refresh'; return $this->step->$migrateRefreshFnc($this); } } class setupStepMigrate extends setupStep { var $header_image = "geticon.php?context=applications&icon=utilities-system-monitor&size=48"; /* Root object classes */ var $rootOC_details = []; /* Entries needing migration */ protected $orgUnits_toMigrate = []; protected $accounts_toMigrate = []; protected $outsideUsers_toMigrate = []; protected $outsideOGroups_toMigrate = []; protected $outsidePosixGroups_toMigrate = []; /* check for multiple use of same uidNumber */ var $check_uidNumber = [];
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
/* check for multiple use of same gidNumber */ var $check_gidNumber = []; /* Defaults ACL roles */ var $defaultRoles; /* Limit of objects to check/migrate at once to avoid timeouts or memory overflow */ static protected $objectNumberLimit = 5000; static function getAttributesInfo (): array { return [ 'checks' => [ 'class' => ['fullwidth'], 'name' => _('PHP module and extension checks'), 'template' => get_template_path("setup_migrate.tpl", TRUE, dirname(__FILE__)), 'attrs' => [ new FakeAttribute('checks') ] ], ]; } function __construct ($parent) { parent::__construct($parent); $this->fill_defaultRoles(); } function update_strings () { $this->s_short_name = _('LDAP inspection'); $this->s_title = _('LDAP inspection'); $this->s_description = _('Analyze your current LDAP for FusionDirectory compatibility'); } function fill_defaultRoles () { $this->defaultRoles = [ [ 'cn' => 'manager', 'description' => _('Give all rights on users in the given branch'), 'objectclass' => ['top', 'gosaRole'], 'gosaAclTemplate' => '0:user/user;cmdrw,user/posixAccount;cmdrw' ], [ 'cn' => 'editowninfos', 'description' => _('Allow users to edit their own information (main tab and posix use only on base)'), 'objectclass' => ['top', 'gosaRole'], 'gosaAclTemplate' => '0:user/user;srw,user/posixAccount;srw' ], [ 'cn' => 'editownpwd', 'description' => _('Allow users to edit their own password (use only on base)'), 'objectclass' => ['top', 'gosaRole'], 'gosaAclTemplate' => '0:user/user;s#userPassword;rw' ], ]; } function initialize_checks () { global $config; $config->resetDepartmentCache(); $checks = [ 'baseOC' => new StepMigrateCheck($this, 'baseOC', _('Inspecting object classes in root object')), 'permissions' => new StepMigrateCheck($this, 'permissions', _('Checking permission for LDAP database')), 'accounts' => new StepMigrateCheck($this, 'accounts', _('Checking for invisible users')), 'adminAccount' => new StepMigrateCheck($this, 'adminAccount', _('Checking for super administrator')),
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
'defaultACLs' => new StepMigrateCheck($this, 'defaultACLs', _('Checking for default ACL roles and groups')), 'outsideUsers' => new StepMigrateCheck($this, 'outsideUsers', _('Checking for users outside the people tree')), 'outsideOGroups' => new StepMigrateCheck($this, 'outsideOGroups', _('Checking for groups outside the groups tree')), 'orgUnits' => new StepMigrateCheck($this, 'orgUnits', _('Checking for invisible departments')), ]; if (class_available('posixAccount')) { $checks['outsidePosixGroups'] = new StepMigrateCheck($this, 'outsidePosixGroups', _('Checking for POSIX groups outside the groups tree')); $checks['uidNumber'] = new StepMigrateCheck($this, 'uidNumber', _('Checking for duplicate UID numbers')); $checks['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)) { 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); } public function readPost () { if (ini_get('max_execution_time') < 180) { set_time_limit(180); } $this->is_completed = TRUE; parent::readPost(); if (isset($_POST['reload'])) { $this->checks = []; } foreach ($this->checks as $check) { $check->readPost(); } } public function update (): bool { if (ini_get('max_execution_time') < 180) { set_time_limit(180); } if (empty($this->checks)) { $this->initialize_checks(); foreach ($this->checks as $check) { $check->run(); } } return parent::update(); } /* 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. */
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
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(TRUE); /* Root object doesn't exists */ if (!in_array("gosaDepartment", $attrs['objectClass'])) { $this->rootOC_details = []; $mods = []; /* 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.") ); } /* Try to detect base class type, e.g. is it a dcObject */ $dep_types = departmentManagement::getDepartmentTypes(); $dep_type = ""; /* This allow us to filter it as if it was already migrated */ $attrs['objectClass'][] = 'gosaDepartment'; 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];
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
} $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() ); } /* Create & remove of dummy object was successful */ return ''; } function check_baseOC_migrate (&$checkobj) { /* Refresh $this->rootOC_details */ $checkobj->run(); $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) { $error = new FusionDirectoryLdapError($config->current['BASE'], LDAP_MOD, $ldap->get_error(), $ldap->get_errno()); $error->display(); } $this->checks['adminAccount']->run(); return $res;
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
} 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().random_int(0, 999999); $dn = 'ou='.$name.','.$config->current['BASE']; $testEntry = []; $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.') ); } /* Try to create dummy object */ $ldap->cd($dn); $res = $ldap->add($testEntry); $ldap->cat($dn); if (!$ldap->count()) { logging::log('error', 'setup/'.get_class($this), $dn, [], $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()) { logging::log('error', 'setup/'.get_class($this), $dn, [], $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_accounts (&$checkobj) { global $config;
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
$ldap = $config->get_ldap_link(); $ldap->set_size_limit(static::$objectNumberLimit); /* Remember old list of invisible users, to be able to set * the 'html checked' status for the checkboxes again */ $old = $this->accounts_toMigrate; $this->accounts_toMigrate = []; /* Get all invisible users */ $ldap->cd($config->current['BASE']); $res = $ldap->search( '(&'. '(|'. '(objectClass=posixAccount)'. '(objectClass=person)'. '(objectClass=OpenLDAPperson)'. ')'. '(!(objectClass=inetOrgPerson))'. '(uid=*)'. '(!(uid=*$))'. ')', ['objectClass','sn','givenName','cn','uid'] ); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); } $sizeLimitHit = $ldap->hitSizeLimit(); $accountsCount = $ldap->count(); while ($attrs = $ldap->fetch(TRUE)) { $base = preg_replace('/^[^,]+,/', '', $attrs['dn']); /* Build groupid depending on base and objectClasses */ $groupid = md5($base.implode('', $attrs['objectClass'])); if (!isset($this->accounts_toMigrate[$groupid])) { $this->accounts_toMigrate[$groupid] = [ /* Set objects to selected, that were selected before reload */ 'checked' => ($old[$groupid]['checked'] ?? FALSE), 'objects' => [], 'base' => $base, 'classes' => $attrs['objectClass'], ]; } $attrs['before'] = ''; $attrs['after'] = ''; $this->accounts_toMigrate[$groupid]['objects'][base64_encode($attrs['dn'])] = $attrs; } if (count($this->accounts_toMigrate) == 0) { /* No invisible */ return ''; } else { if ($sizeLimitHit) { $message = sprintf( _('Found more than %d user(s) that will not be visible in FusionDirectory or which are incomplete.'), static::$objectNumberLimit ); } else { $message = sprintf( _('Found %d user(s) that will not be visible in FusionDirectory or which are incomplete.'), $accountsCount ); }
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
throw new CheckFailedException( "<div style='color:#F0A500'>"._("Warning")."</div>", $message.$checkobj->submit() ); } } function check_accounts_migrate (&$checkobj) { $this->check_multipleGeneric_migrate( $checkobj, [ 'title' => _('User migration'), 'outside' => FALSE, ] ); } function check_accounts_migrate_refresh (&$checkobj) { return $this->check_multipleGeneric_migrate_refresh( $checkobj, [ 'title' => _('User migration'), 'outside' => FALSE, ] ); } function check_accounts_migrate_confirm (&$checkobj, $only_ldif = FALSE) { return $this->check_multipleGeneric_migrate_confirm( $checkobj, ['inetOrgPerson','organizationalPerson','person'], [], $only_ldif ); } function check_multipleGeneric_migrate (&$checkobj, $infos) { $var = $checkobj->name.'_toMigrate'; $infos['entries'] = $this->$var; $this->openDialog(new StepMigrateDialog($checkobj, 'setup_migrate_accounts.tpl', $infos)); } function check_multipleGeneric_migrate_refresh (&$checkobj, $infos) { if (isset($_POST['dialog_showchanges'])) { /* Show changes */ $fnc = 'check_'.$checkobj->name.'_migrate_confirm'; $this->$fnc($checkobj, TRUE); } else { /* Hide changes */ $checkobj->run(); } $var = $checkobj->name.'_toMigrate'; $infos['entries'] = $this->$var; return $infos; } function check_multipleGeneric_migrate_confirm (&$checkobj, $oc, $mandatory, $only_ldif) { global $config; $ldap = $config->get_ldap_link(); /* Add objectClasses to the selected entries */
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
$var = $checkobj->name.'_toMigrate'; foreach ($this->$var as $key => &$entry) { $entry['checked'] = isset($_POST['migrate_'.$key]); if ($entry['checked']) { if (isset($entry['objects'])) { $objects =& $entry['objects']; } else { $objects = [&$entry]; } foreach ($objects as &$object) { /* Get old objectClasses */ $ldap->cat($object['dn'], array_merge(['objectClass'], array_keys($mandatory))); $attrs = $ldap->fetch(TRUE); /* Create new objectClass array */ $new_attrs = []; $new_attrs['objectClass'] = $oc; for ($i = 0; $i < $attrs['objectClass']['count']; $i++) { if (!in_array_ics($attrs['objectClass'][$i], $new_attrs['objectClass'])) { $new_attrs['objectClass'][] = $attrs['objectClass'][$i]; } } /* Append mandatories if missing */ foreach ($mandatory as $name => $value) { if (!isset($attrs[$name])) { $new_attrs[$name] = $value; } } /* Set info attributes for current object, * or write changes to the ldap database */ if ($only_ldif) { $object['before'] = $this->array_to_ldif($attrs); $object['after'] = $this->array_to_ldif($new_attrs); } else { $ldap->cd($attrs['dn']); if (!$ldap->modify($new_attrs)) { $error = new FusionDirectoryError( nl2br(sprintf( htmlescape(_("Cannot migrate entry \"%s\":\n\n%s")), htmlescape($attrs['dn']), '<i>'.htmlescape($ldap->get_error()).'</i>' )) ); $error->display(); return FALSE; } } } unset($object); unset($objects); } } unset($entry); return TRUE; } /* Check Acls if there is at least one object with acls defined */ function check_adminAccount (&$checkobj) { global $config; /* Establish ldap connection */ $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $res = $ldap->cat($config->current['BASE'], ['gosaAclEntry']); if (!$res) { throw new CheckFailedException(
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
_('LDAP query failed'), _('Possibly the "root object" is missing.') ); } else { $FD_admin_found = FALSE; $attrs = $ldap->fetch(); /* Check if a valid FusionDirectory admin exists -> gosaAclEntry for an existing and accessible user. */ $valid_users = []; $valid_groups = []; $valid_roles = []; if (isset($attrs['gosaAclEntry'])) { $acls = $attrs['gosaAclEntry']; for ($i = 0; $i < $acls['count']; $i++) { $acl = $acls[$i]; $tmp = explode(':', $acl); if ($tmp[1] == 'subtree') { /* Check if acl owner is a valid FusionDirectory user account */ $ldap->cat(base64_decode($tmp[2]), ['gosaAclTemplate'], '(gosaAclTemplate=*:all;cmdrw)'); if ($ldap->count()) { $members = explode(',', $tmp[3]); foreach ($members as $member) { $member = base64_decode($member); $ldap->cat($member, ['dn','uid','cn','memberUid','roleOccupant','objectClass']); if ($member_attrs = $ldap->fetch()) { if (in_array('inetOrgPerson', $member_attrs['objectClass'])) { $valid_users[] = htmlescape(($member_attrs['uid'][0] ?? $member_attrs['dn'])); $FD_admin_found = TRUE; } elseif (in_array('posixGroup', $member_attrs['objectClass'])) { $val_users = []; if (isset($member_attrs['memberUid'])) { for ($e = 0; $e < $member_attrs['memberUid']['count']; $e++) { $ldap->search('(&(objectClass=inetOrgPerson)(uid='.ldap_escape_f($member_attrs['memberUid'][$e]).'))', ['uid','dn']); if ($user_attrs = $ldap->fetch()) { $val_users[] = htmlescape(($user_attrs['uid'][0] ?? $user_attrs['dn'])); } } } if (!empty($val_users)) { $valid_groups[] = htmlescape($member_attrs['cn'][0]).'(<i>'.implode(', ', $val_users).'</i>)'; $FD_admin_found = TRUE; } } elseif (in_array('organizationalRole', $member_attrs['objectClass'])) { $val_users = []; if (isset($member_attrs['roleOccupant'])) { for ($e = 0; $e < $member_attrs['roleOccupant']['count']; $e ++) { $ldap->cat($member_attrs['roleOccupant'][$e], ['uid','dn'], '(objectClass=inetOrgPerson)'); if ($user_attrs = $ldap->fetch()) { $val_users[] = htmlescape(($user_attrs['uid'][0] ?? $user_attrs['dn'])); } } } if (!empty($val_users)) { $valid_roles[] = htmlescape($member_attrs['cn'][0]).'(<i>'.implode(', ', $val_users).'</i>)'; $FD_admin_found = TRUE; } } } } } } } } /* Print out results */
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
if ($FD_admin_found) { $str = ''; if (!empty($valid_users)) { $str .= '<b>'._('Users').'</b>:&nbsp;'.implode(', ', $valid_users).'<br/>'; } if (!empty($valid_groups)) { $str .= '<b>'._('Groups').'</b>:&nbsp;'.implode(', ', $valid_groups).'<br/>'; } if (!empty($valid_roles)) { $str .= '<b>'._('Roles').'</b>:&nbsp;'.implode(', ', $valid_roles).'<br/>'; } return $str; } else { throw new CheckFailedException( _('Failed'), _('There is no FusionDirectory administrator account in your LDAP directory.').'&nbsp;'. $checkobj->submit(_('Create'), 'create') ); } } } function check_adminAccount_create (&$checkobj) { $infos = [ 'uid' => 'fd-admin', 'password' => '', 'password2' => '', ]; $this->openDialog(new StepMigrateDialog($checkobj, 'setup_migrate_adminAccount.tpl', $infos)); } function check_adminAccount_migrate_confirm (&$checkobj) { global $config, $ui; $ui->setCurrentBase($config->current['BASE']); /* Creating role */ $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->search('(&(objectClass=gosaRole)(gosaAclTemplate=*:all;cmdrw))', ['dn']); if ($attrs = $ldap->fetch()) { $roledn = $attrs['dn']; } else { $tabObject = objects::create('aclRole'); $baseObject = $tabObject->getBaseObject(); $baseObject->cn = 'admin'; $baseObject->description = _('Gives all rights on all objects'); $baseObject->gosaAclTemplate = [['all' => ['0' => 'cmdrw']]]; $tabObject->save(); $roledn = $tabObject->dn; } /* Creating user */ $tabObject = objects::create('user'); $baseObject = $tabObject->getBaseObject(); $baseObject->givenName = 'System'; $baseObject->sn = 'Administrator'; $baseObject->uid = $_POST['uid']; $baseObject->userPassword = [ '', $_POST['userPassword_password'], $_POST['userPassword_password2'], '', FALSE ];
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
$tabObject->update(); $errors = $tabObject->save(); if (!empty($errors)) { msg_dialog::displayChecks($errors); return FALSE; } $admindn = $tabObject->dn; /* Assigning role */ $tabObject = objects::open($config->current['BASE'], 'aclAssignment'); $baseObject = $tabObject->getBaseObject(); $assignments = $baseObject->gosaAclEntry; array_unshift( $assignments, [ 'scope' => 'subtree', 'role' => $roledn, 'members' => [$admindn], ] ); $baseObject->gosaAclEntry = $assignments; $tabObject->save(); return TRUE; } function check_adminAccount_migrate_refresh (&$checkobj) { return [ 'uid' => $_POST['uid'], 'password' => $_POST['userPassword_password'], 'password2' => $_POST['userPassword_password2'], ]; } /* Check if default roles and groupes have been inserted */ function check_defaultACLs (&$checkobj) { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $res = $ldap->cat($config->current['BASE']); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); } $existings = 0; foreach ($this->defaultRoles as $role) { $dn = 'cn='.$role['cn'].','.get_ou('aclRoleRDN').$config->current['BASE']; $ldap->cat($dn, ['dn']); if ($ldap->count() > 0) { $existings++; } } $status = ($existings == count($this->defaultRoles)); if ($existings == 0) { $checkobj->msg = _('Default ACL roles have not been inserted'); } elseif ($existings < count($this->defaultRoles)) { $checkobj->msg = _('Some default ACL roles are missing'); } else { $checkobj->msg = _('Default ACL roles have been inserted'); } if ($status === FALSE) { throw new CheckFailedException( $checkobj->msg,
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
'&nbsp;'.$checkobj->submit() ); } else { return ''; } } function check_defaultACLs_migrate (&$checkobj) { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); foreach ($this->defaultRoles as $role) { $dn = 'cn='.$role['cn'].','.get_ou('aclRoleRDN').$config->current['BASE']; $ldap->cat($dn); if ($ldap->count() == 0) { $ldap->cd($config->current['BASE']); try { $ldap->create_missing_trees(get_ou('aclRoleRDN').$config->current['BASE']); } catch (FusionDirectoryError $error) { $error->display(); } $ldap->cd($dn); $ldap->add($role); if (!$ldap->success()) { $error = new FusionDirectoryError( nl2br(sprintf( htmlescape(_("Cannot add ACL role \"%s\":\n\n%s")), htmlescape($dn), '<i>'.htmlescape($ldap->get_error()).'</i>' )) ); $error->display(); return FALSE; } } } $checkobj->run(); return TRUE; } /* Search for users outside the people ou */ function check_outsideUsers (&$checkobj) { list($sizeLimitHit,$count) = $this->check_outsideObjects_generic($checkobj, '(&(objectClass=inetOrgPerson)(!(uid=*$)))', 'userRDN'); if ($count > 0) { if ($sizeLimitHit) { $message = sprintf(_('Found more than %d user(s) outside the configured tree "%s".'), static::$objectNumberLimit, trim(get_ou('userRDN'))); } else { $message = sprintf(_('Found %d user(s) outside the configured tree "%s".'), $count, trim(get_ou('userRDN'))); } throw new CheckFailedException( "<div style='color:#F0A500'>"._("Warning")."</div>", $message. $checkobj->submit() ); } } function check_outsideObjects_generic (&$checkobj, $filter, $ou) { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); /*********** * Check if objects are within a valid department. (peopleou,gosaDepartment,base) ***********/
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
$sizeLimitHit = FALSE; $var = $checkobj->name.'_toMigrate'; $this->$var = []; $objects_ou = trim(get_ou($ou)); $cookie = ''; $count = 0; do { $res = $ldap->search($filter, ['dn','objectClass'], 'subtree', [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'value' => ['size' => 500, 'cookie' => $cookie]]] ); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); } try { list($errcode, $matcheddn, $errmsg, $referrals, $controls) = $ldap->parse_result(); } catch (FusionDirectoryException $e) { throw new CheckFailedException( _('LDAP result parsing failed'), $e->getMessage() ); } if ($errcode !== 0) { throw new CheckFailedException( _('LDAP error'), $errcode.' - '.ldap_err2str($errcode).(!empty($errmsg) ? ' ('.$errmsg.')' : '') ); } if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) { // You need to pass the cookie from the last call to the next one $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie']; } else { $cookie = ''; } while ($attrs = $ldap->fetch(TRUE)) { $object_base = preg_replace('/^[^,]+,'.preg_quote($objects_ou, '/').'/i', '', $attrs['dn'], 1, $pregCount); $base = preg_replace('/^[^,]+,/', '', $attrs['dn']); /* Check if entry is in a valid department */ if (($pregCount === 0) || !in_array($object_base, $config->getDepartmentList())) { /* Build groupid depending on base and objectClasses */ $groupid = md5($base.implode('', $attrs['objectClass'])); if (!isset($this->{$var}[$groupid])) { $this->{$var}[$groupid] = [ 'checked' => FALSE, 'objects' => [], 'base' => $base, 'classes' => $attrs['objectClass'], ]; } $attrs['ldif'] = ''; $this->{$var}[$groupid]['objects'][base64_encode($attrs['dn'])] = $attrs; if (++$count >= static::$objectNumberLimit) { $sizeLimitHit = TRUE; break 2; } } } // Empty cookie means last page } while (!empty($cookie)); return [$sizeLimitHit, $count]; }
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
function check_outsideUsers_migrate (&$checkobj) { global $config; $this->check_multipleGeneric_migrate( $checkobj, [ 'title' => _('Move users into configured user tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsideUsers_migrate_refresh (&$checkobj) { global $config; return $this->check_multipleGeneric_migrate_refresh( $checkobj, [ 'title' => _('Move users into configured user tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsideUsers_migrate_confirm (&$checkobj, $only_ldif = FALSE, $ou = 'userRDN') { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); /* Check if there was a destination department posted */ if (isset($_POST['destination'])) { $destination_dep = get_ou($ou).$_POST['destination']; } else { $error = new FusionDirectoryError(htmlescape(_('Cannot move entries to the requested department!'))); $error->display(); return FALSE; } $var = $checkobj->name.'_toMigrate'; foreach ($this->$var as $b_dn => &$entry) { $entry['checked'] = isset($_POST['migrate_'.$b_dn]); if ($entry['checked']) { foreach ($entry['objects'] as &$object) { $dn = $object['dn']; $d_dn = preg_replace('/,.*$/', ','.$destination_dep, $dn); if ($only_ldif) { $object['ldif'] = nl2br(htmlescape(sprintf(_("Entry will be moved from:\n\t%s\nto:\n\t%s"), $dn, $d_dn))); /* Check if there are references to this object */ $ldap->search('(&(member='.ldap_escape_f($dn).')(|(objectClass=gosaGroupOfNames)(objectClass=groupOfNames)))', ['dn']); $refs = ''; while ($attrs = $ldap->fetch()) { $ref_dn = $attrs['dn']; $refs .= "<br/>\t".$ref_dn; } if (!empty($refs)) { $entry['ldif'] .= '<br/><br/><i>'._('The following references will be updated').':</i>'.$refs; } } else { $object['ldif'] = ''; $this->move($dn, $d_dn); } } unset($object); }
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
} unset($entry); return TRUE; } /* Search for groups outside the group ou */ function check_outsideOGroups (&$checkobj) { list($sizeLimitHit,$count) = $this->check_outsideObjects_generic($checkobj, '(objectClass=groupOfNames)', 'ogroupRDN'); if ($count > 0) { if ($sizeLimitHit) { $message = sprintf(_('Found more than %d groups outside the configured tree "%s".'), static::$objectNumberLimit, trim(get_ou('ogroupRDN'))); } else { $message = sprintf(_('Found %d groups outside the configured tree "%s".'), $count, trim(get_ou('ogroupRDN'))); } throw new CheckFailedException( '<div style="color:#F0A500">'._('Warning').'</div>', $message. $checkobj->submit() ); } } function check_outsideOGroups_migrate (&$checkobj) { global $config; $this->check_multipleGeneric_migrate( $checkobj, [ 'title' => _('Move groups into configured groups tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsideOGroups_migrate_refresh (&$checkobj) { global $config; return $this->check_multipleGeneric_migrate_refresh( $checkobj, [ 'title' => _('Move groups into configured groups tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsideOGroups_migrate_confirm (&$checkobj, $only_ldif = FALSE) { return $this->check_outsideUsers_migrate_confirm($checkobj, $only_ldif, 'ogroupRDN'); } /* Search for POSIX groups outside the group ou */ function check_outsidePosixGroups (&$checkobj) { list($sizeLimitHit,$count) = $this->check_outsideObjects_generic($checkobj, '(objectClass=posixGroup)', 'groupRDN'); if ($count > 0) { if ($sizeLimitHit) { $message = sprintf(_('Found more than %d POSIX groups outside the configured tree "%s".'), static::$objectNumberLimit, trim(get_ou('groupRDN'))); } else { $message = sprintf(_('Found %d POSIX groups outside the configured tree "%s".'), $count, trim(get_ou('groupRDN'))); } throw new CheckFailedException(
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
'<div style="color:#F0A500">'._('Warning').'</div>', $message. $checkobj->submit() ); } } function check_outsidePosixGroups_migrate (&$checkobj) { global $config; $this->check_multipleGeneric_migrate( $checkobj, [ 'title' => _('Move POSIX groups into configured groups tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsidePosixGroups_migrate_refresh (&$checkobj) { global $config; return $this->check_multipleGeneric_migrate_refresh( $checkobj, [ 'title' => _('Move POSIX groups into configured groups tree'), 'outside' => TRUE, 'ous' => $config->getDepartmentList(), 'destination' => (isset($_POST['destination']) ? $_POST['destination'] : ''), ] ); } function check_outsidePosixGroups_migrate_confirm (&$checkobj, $only_ldif = FALSE) { return $this->check_outsideUsers_migrate_confirm($checkobj, $only_ldif, 'groupRDN'); } /* Check if there are invisible organizational Units */ function check_orgUnits (&$checkobj) { global $config; $ldap = $config->get_ldap_link(); $ldap->set_size_limit(static::$objectNumberLimit); $old = $this->orgUnits_toMigrate; $this->orgUnits_toMigrate = []; /* Skip FusionDirectory internal departments */ $skip_dns = [ '/ou=fusiondirectory,'.preg_quote($config->current['BASE']).'$/', '/^ou=systems,/', '/ou=snapshots,/' ]; foreach (objects::types() as $type) { $infos = objects::infos($type); if (isset($infos['ou']) && ($infos['ou'] != '')) { $skip_dns[] = '/^'.preg_quote($infos['ou'], '/').'/'; } } /* Get all invisible departments */ $ldap->cd($config->current['BASE']); $res = $ldap->search('(&(objectClass=organizationalUnit)(!(objectClass=gosaDepartment)))', ['ou','description','dn']); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.')
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
); } if ($ldap->hitSizeLimit()) { throw new CheckFailedException( _('Size limit hit'), sprintf(_('Size limit of %d hit. Please check this manually'), static::$objectNumberLimit) ); } $sizeLimitHit = FALSE; while ($attrs = $ldap->fetch(TRUE)) { foreach ($skip_dns as $skip_dn) { /* Filter out FusionDirectory internal departments */ if (preg_match($skip_dn, $attrs['dn'])) { continue 2; } } $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->orgUnits_toMigrate[base64_encode($attrs['dn'])] = $attrs; if (count($this->orgUnits_toMigrate) >= static::$objectNumberLimit) { $sizeLimitHit = TRUE; break; } } /* If we have no invisible departments found * tell the user that everything is ok */ if (count($this->orgUnits_toMigrate) == 0) { return ''; } else { if ($sizeLimitHit) { $message = sprintf(_('Found more than %d department(s) that will not be visible in FusionDirectory.'), static::$objectNumberLimit); } else { $message = sprintf(_('Found %d department(s) that will not be visible in FusionDirectory.'), count($this->orgUnits_toMigrate)); } throw new CheckFailedException( '<font style="color:#FFA500">'._('Warning').'</font>', $message. $checkobj->submit() ); } } function check_orgUnits_migrate (&$checkobj) { $this->check_multipleGeneric_migrate( $checkobj, [ 'title' => _('Department migration'), 'outside' => FALSE, ] ); } function check_orgUnits_migrate_refresh (&$checkobj) { return $this->check_multipleGeneric_migrate_refresh( $checkobj, [ 'title' => _('Department migration'), 'outside' => FALSE,
1401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
] ); } function check_orgUnits_migrate_confirm (&$checkobj, $only_ldif = FALSE) { return $this->check_multipleGeneric_migrate_confirm( $checkobj, ['gosaDepartment'], ['description' => 'FusionDirectory department'], $only_ldif ); } /* Check if there are uidNumbers which are used more than once */ function check_uidNumber (&$checkobj) { $this->check_duplicatesGeneric($checkobj, 'posixAccount'); } /* Check if there are duplicated gidNumbers present in ldap */ function check_gidNumber (&$checkobj) { $this->check_duplicatesGeneric($checkobj, 'posixGroup'); } /* Generic function to check duplicated values */ function check_duplicatesGeneric (&$checkobj, $oc) { global $config; $ldap = $config->get_ldap_link(); $attribute = $checkobj->name; $duplicates = 'check_'.$checkobj->name; $ldap->cd($config->current['BASE']); $res = $ldap->search('(&(objectClass='.$oc.')('.$attribute.'=*))', ['dn',$attribute]); if (!$res) { throw new CheckFailedException( _('LDAP query failed'), _('Possibly the "root object" is missing.') ); } $this->$duplicates = []; $tmp = []; while ($attrs = $ldap->fetch()) { $tmp[$attrs[$attribute][0]][] = $attrs['dn']; } foreach ($tmp as $value => $dns) { if (count($dns) > 1) { foreach ($dns as $dn) { $this->{$duplicates}[$dn] = $value; } } } if (count($this->$duplicates) == 0) { return ''; } else { $list = '<ul>'; foreach ($this->$duplicates as $dn => $value) { $list .= '<li>'.$dn.' ('.$value.')</li>'; } $list .= '</ul>'; throw new CheckFailedException( '<div style="color:#F0A500">'._('Warning').'</div>', sprintf(_('Found %d duplicate values for attribute "'.$attribute.'":%s'), count($this->$duplicates), $list) );
1471147214731474
} } }