class_simplePlugin.inc 67.65 KiB
<?php
/*
  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
  Copyright (C) 2012-2018  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.
/*!
 * \file class_simplePlugin.inc
 * Source code for the class simplePlugin
/*! \brief This class is made for easy plugin creation for editing LDAP attributes
class simplePlugin
  /*! \brief This attribute store all information about attributes */
  public $attributesInfo;
  /*! \brief This attribute store references toward attributes
   * associative array that stores attributeLdapName => reference on object
  public $attributesAccess = [];
  /*!
    \brief Mark plugin as account
    Defines whether this plugin is defined as an account or not.
    This has consequences for the plugin to be saved from tab
    mode. If it is set to 'FALSE' the tab will call the delete
    function, else the save function. Should be set to 'TRUE' if
    the construtor detects a valid LDAP object.
    \sa simplePlugin::is_this_account()
  public $is_account            = FALSE;
  public $initially_was_account = FALSE;
  public $ignore_account        = FALSE;
  public $acl_base      = '';
  public $acl_category  = '';
  /*! \brief dn of the opened object */
  public $dn      = '';
  /*! \brief original dn of the opened object */
  public $orig_dn = '';
  /*!
   * \brief Reference to parent object
   * This variable is used when the plugin is included in tabs
   * and keeps reference to the tab class. Communication to other
   * tabs is possible by 'name'. So the 'fax' plugin can ask the
   * 'userinfo' plugin for the fax number.
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
* * \sa simpleTabs */ public $parent = NULL; /*! \brief Mark plugin as template Defines whether we are editing a template or a normal object. Has consequences on the way execute() shows the formular and how save() puts the data to LDAP. */ public $is_template = FALSE; /*! \brief Represent temporary LDAP data This should only be used internally. */ public $attrs = []; /*! \brief The objectClasses set by this tab */ protected $objectclasses = []; /*! \brief The state of the attributes when we opened the object */ protected $saved_attributes = []; /*! \brief Do we want a header allowing to able/disable this plugin */ protected $displayHeader = FALSE; /*! \brief Is this plugin the main tab, the one that handle the object itself */ protected $mainTab = FALSE; protected $header = ""; protected $templatePath; protected $dialog = FALSE; /*! \brief Are we executed in a edit-mode environment? (this is FALSE if we're called from management, TRUE if we're called from a main.inc) */ protected $needEditMode = FALSE; /*! \brief Attributes that needs to be initialized before the others */ protected $preInitAttributes = []; /*! \brief FALSE to disable inheritance. Array like array ('objectClass' => 'attribute') to specify oc of the groups it might be inherited from */ protected $inheritance = FALSE; protected $member_of_group = FALSE; protected $editing_group = NULL; protected $group_attrs = []; /*! \brief Used when the entry is opened as "readonly" due to locks */ protected $read_only = FALSE; /*! \brief Last LDAP error (used by logging calls from post_* methods) */ protected $ldap_error; /*! * \brief Object entry CSN * * If an entry was edited while we have edited the entry too, * an error message will be shown. * To configure this check correctly read the FAQ. */ protected $entryCSN = ''; private $hadSubobjects = FALSE;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
/*! \brief constructor * * \param string $dn The dn of this instance * \param Object $object An object to copy values from * \param Object $parent A parent instance, usually a simpleTabs instance. * \param boolean $mainTab Whether or not this is the main tab * \param array $attributesInfo An attributesInfo array, if NULL, getAttributesInfo will be used. * */ function __construct ($dn = NULL, $object = NULL, $parent = NULL, $mainTab = FALSE, $attributesInfo = NULL) { global $config; $this->dn = $dn; $this->parent = $parent; $this->mainTab = $mainTab; if ($attributesInfo === NULL) { $attributesInfo = $this->getAttributesInfo(); } if (!$this->displayHeader) { // If we don't display the header to activate/deactive the plugin, that means it's always activated $this->ignore_account = TRUE; } $this->attributesInfo = []; foreach ($attributesInfo as $section => $sectionInfo) { $attrs = []; foreach ($sectionInfo['attrs'] as $attr) { $name = $attr->getLdapName(); if (isset($attrs[$name])) { // We check that there is no duplicated attribute name trigger_error("Duplicated attribute LDAP name '$name' in a simplePlugin subclass"); } // We make so that attribute have their LDAP name as key // That allow the plugin to use $this->attributesInfo[$sectionName]['attrs'][$myLdapName] to retreive the attribute info. $attrs[$name] = $attr; } $sectionInfo['attrs'] = $attrs; $this->attributesInfo[$section] = $sectionInfo; foreach ($this->attributesInfo[$section]['attrs'] as $name => $attr) { if (isset($this->attributesAccess[$name])) { // We check that there is no duplicated attribute name trigger_error("Duplicated attribute LDAP name '$name' in a simplePlugin subclass"); } $this->attributesAccess[$name] =& $this->attributesInfo[$section]['attrs'][$name]; unset($this->$name); } } /* Ensure that we've a valid acl_category set */ if (empty($this->acl_category)) { $tmp = pluglist::pluginInfos(get_class($this)); if (isset($tmp['plCategory'])) { $c = key($tmp['plCategory']); if (is_numeric($c)) { $c = $tmp['plCategory'][0]; } $this->acl_category = $c.'/'; } } /* Handle read only */ if ($this->dn != 'new') { /* Check if this entry was opened in read only mode */ if (isset($_POST['open_readonly'])) { if (session::is_set('LOCK_CACHE')) { $cache = session::get('LOCK_CACHE'); if (isset($cache['READ_ONLY'][$this->dn])) { $this->read_only = TRUE;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} } } /* Save current dn as acl_base */ $this->acl_base = $this->dn; } /* Load LDAP data */ if (($this->dn != 'new' && $this->dn !== NULL) || ($object !== NULL)) { /* Load data to 'attrs' */ if ($object !== NULL) { /* From object */ $this->attrs = $object->attrs; if (isset($object->is_template)) { $this->setTemplate($object->is_template); } } else { /* From LDAP */ $ldap = $config->get_ldap_link(); $ldap->cat($this->dn); $this->attrs = $ldap->fetch(); if (empty($this->attrs)) { throw new NonExistingLdapNodeException('Could not open dn '.$this->dn); } if ($this->mainTab) { /* Make sure that initially_was_account is TRUE if we loaded an LDAP node, * even if it’s missing an objectClass */ $this->is_account = TRUE; } } /* Set the template flag according to the existence of objectClass fdTemplate */ if (isset($this->attrs['objectClass'])) { if (in_array_ics ('fdTemplate', $this->attrs['objectClass'])) { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, 'found', 'Template check'); $this->setTemplate(TRUE); $this->templateLoadAttrs($this->attrs); } } /* Is Account? */ if ($this->is_this_account($this->attrs)) { $this->is_account = TRUE; @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, 'found', 'Object check'); } } if (is_array($this->inheritance)) { /* Check group membership */ $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); foreach ($this->inheritance as $oc => $at) { if ($this->mainTab) { $filter = '(&(objectClass='.$oc.')('.$at.'='.ldap_escape_f($this->dn).'))'; } else { $filter = '(&(objectClass='.$oc.')'.$this->getObjectClassFilter().'('.$at.'='.ldap_escape_f($this->dn).'))'; } $ldap->search($filter, $this->attributes); if ($ldap->count() == 1) { $this->member_of_group = TRUE; $attrs = $ldap->fetch(); $this->group_attrs = $attrs; break; } } } /* Save initial account state */ $this->initially_was_account = $this->is_account;
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
$this->loadAttributes(); $this->prepareSavedAttributes(); $this->orig_dn = $dn; if ($this->mainTab) { $this->is_account = TRUE; $this->entryCSN = getEntryCSN($this->dn); } if (!isset($this->templatePath)) { $this->templatePath = get_template_path('simpleplugin.tpl'); } } protected function loadAttributes() { // We load attributes values // First the one flagged as preInit foreach ($this->preInitAttributes as $attr) { $this->attributesAccess[$attr]->setParent($this); $this->attributesAccess[$attr]->loadValue($this->attrs); } // Then the others foreach ($this->attributesInfo as &$sectionInfo) { foreach ($sectionInfo['attrs'] as $name => &$attr) { if (in_array($name, $this->preInitAttributes)) { /* skip the preInit ones */ continue; } $attr->setParent($this); $attr->loadValue($this->attrs); } unset($attr); } unset($sectionInfo); } function is_this_account($attrs) { $found = TRUE; foreach ($this->objectclasses as $obj) { if (preg_match('/^top$/i', $obj)) { continue; } if (!isset($attrs['objectClass']) || !in_array_ics ($obj, $attrs['objectClass'])) { $found = FALSE; break; } } return $found; } function setTemplate ($bool) { $this->is_template = $bool; if ($this->is_template && $this->mainTab) { /* Unshift special section for template infos */ $this->attributesInfo = array_merge( [ '_template' => [ 'class' => ['fullwidth'], 'name' => _('Template settings'), 'attrs' => [ '_template_cn' => new StringAttribute( _('Template name'), _('This is the name of the template'), '_template_cn', TRUE, '', 'template_cn'
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
) ] ], '_template_dummy' => [ 'class' => ['invisible'], 'name' => '_template_dummy', 'attrs' => [] ] ], $this->attributesInfo ); $this->attributesAccess['_template_cn'] =& $this->attributesInfo['_template']['attrs']['_template_cn']; $this->attributesAccess['_template_cn']->setInLdap(FALSE); $this->attributesAccess['_template_cn']->setValue($this->_template_cn); $this->attributesAccess['_template_cn']->setParent($this); unset($this->_template_cn); } } protected function templateLoadAttrs(array $template_attrs) { if ($this->mainTab) { $this->_template_cn = $template_attrs['cn'][0]; } $this->attrs = templateHandling::fieldsFromLDAP($template_attrs); } protected function templateSaveAttrs() { global $config; $ldap = $config->get_ldap_link(); $ldap->cat($this->dn); $template_attrs = $ldap->fetch(); if (!$template_attrs) { if (!$this->mainTab) { trigger_error('It seems main tab has not been saved.'); } $template_attrs = [ 'objectClass' => ['fdTemplate'], 'fdTemplateField' => [] ]; } $template_attrs = templateHandling::fieldsToLDAP($template_attrs, $this->attrs); if ($this->mainTab) { $template_attrs['cn'] = $this->_template_cn; } return $template_attrs; } /*! \brief This function returns an LDAP filter for this plugin object classes */ function getObjectClassFilter () { if (!empty($this->objectclasses)) { return '(&(objectClass='.implode(')(objectClass=', $this->objectclasses).'))'; } else { return ''; } } /*! \brief This function allows to use the syntax $plugin->attributeName to get attributes values * * It calls the getValue method on the concerned attribute * It also adds the $plugin->attribtues syntax to get attributes list */ public function __get($name) { if ($name == 'attributes') { $plugin = $this; return array_filter(array_keys($this->attributesAccess),
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
function ($a) use ($plugin) { return $plugin->attributesAccess[$a]->isInLdap(); } ); } elseif (isset($this->attributesAccess[$name])) { return $this->attributesAccess[$name]->getValue(); } else { /* Calling default behaviour */ return $this->$name; } } /*! \brief This function allows to use the syntax $plugin->attributeName to set attributes values It calls the setValue method on the concerned attribute */ public function __set($name, $value) { if ($name == 'attributes') { trigger_error('Tried to set obsolete attribute "attributes" (it is now dynamic)'); } elseif (isset($this->attributesAccess[$name])) { $this->attributesAccess[$name]->setValue($value); } else { /* Calling default behaviour */ $this->$name = $value; } } /*! \brief This function allows to use the syntax isset($plugin->attributeName) It returns FALSE if the attribute has an empty value. */ public function __isset($name) { if ($name == 'attributes') { return TRUE; } return isset($this->attributesAccess[$name]); } /*! \brief This function returns the dn this object should have */ public function compute_dn() { global $config; if (!$this->mainTab) { msg_dialog::display(_('Fatal error'), _('Only main tab can compute dn'), FATAL_ERROR_DIALOG); exit; } if (!isset($this->parent) || !($this->parent instanceof simpleTabs)) { msg_dialog::display( _('Fatal error'), sprintf( _('Could not compute dn: no parent tab class for "%s"'), get_class($this) ), FATAL_ERROR_DIALOG ); exit; } $infos = $this->parent->objectInfos(); if ($infos === FALSE) { msg_dialog::display( _('Fatal error'), sprintf( _('Could not compute dn: could not find objectType infos from tab class "%s"'), get_class($this->parent) ), FATAL_ERROR_DIALOG
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
); exit; } $attr = $infos['mainAttr']; $ou = $infos['ou']; if (isset($this->base)) { $base = $this->base; } else { $base = $config->current['BASE']; } if ($this->is_template) { $dn = 'cn='.ldap_escape_dn($this->_template_cn).',ou=templates,'.$ou.$base; return $dn; } return $attr.'='.ldap_escape_dn($this->attributesAccess[$attr]->computeLdapValue()).','.$ou.$base; } protected function addAttribute($section, $attr) { $name = $attr->getLdapName(); $this->attributesInfo[$section]['attrs'][$name] = $attr; $this->attributesAccess[$name] =& $this->attributesInfo[$section]['attrs'][$name]; $this->attributesAccess[$name]->setParent($this); unset($this->$name); } protected function removeAttribute($section, $id) { unset($this->attributesInfo[$section]['attrs'][$id]); unset($this->attributesAccess[$id]); } /*! * \brief Returns a list of all available departments for this object. * * If this object is new, all departments we are allowed to create a new object in are returned. * If this is an existing object, return all deps we are allowed to move this object to. * Used by BaseSelectorAttribute * * \return array [dn] => "..name" // All deps. we are allowed to act on. */ function get_allowed_bases() { global $config; $deps = []; /* Is this a new object ? Or just an edited existing object */ foreach ($config->idepartments as $dn => $name) { if (!$this->initially_was_account && $this->acl_is_createable($dn)) { $deps[$dn] = $name; } elseif ($this->initially_was_account && $this->acl_is_moveable($dn)) { $deps[$dn] = $name; } } /* Add current base */ if (isset($this->base) && isset($config->idepartments[$this->base])) { $deps[$this->base] = $config->idepartments[$this->base]; } elseif (strtolower($this->dn) != strtolower($config->current['BASE'])) { trigger_error('Cannot return list of departments, no default base found in class '.get_class($this).'. (base is "'.$this->base.'")'); } return $deps; } /*! * \brief Set acl base * * \param string $base */ function set_acl_base($base)
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
{ $this->acl_base = $base; } /*! * \brief Set acl category * * \param string $category */ function set_acl_category($category) { $this->acl_category = "$category/"; } /*! * \brief Move ldap entries from one place to another * * \param string $src_dn the source DN. * * \param string $dst_dn the destination DN. * * \return TRUE on success, error string on failure */ function move($src_dn, $dst_dn) { global $config, $ui; /* Do not move if only case has changed */ if (strtolower($src_dn) == strtolower($dst_dn)) { return TRUE; } /* Try to move with ldap routines */ $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn)); if (!$ldap->rename_dn($src_dn, $dst_dn)) { logging::log('debug', 'Ldap Protocol v3 implementation error, ldap_rename failed.', "FROM: $src_dn -- TO: $dst_dn", [], $ldap->get_error()); @DEBUG(DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, "Rename failed FROM: $src_dn -- TO: $dst_dn", 'Ldap Protocol v3 implementation error. Error:'.$ldap->get_error()); return $ldap->get_error(); } /* Update userinfo if necessary */ if (preg_match('/'.preg_quote($src_dn, '/').'$/i', $ui->dn)) { $ui_dn = preg_replace('/'.preg_quote($src_dn, '/').'$/i', $dst_dn, $ui->dn); logging::log('view', 'acl/'.get_class($this), $this->dn, [], 'Updated userinfo dn from "'.$ui->dn.'" to "'.$ui_dn.'"'); $ui->dn = $ui_dn; } /* Check if departments were moved. If so, force the reload of config->departments */ $ldap->cd($dst_dn); $ldap->search('(objectClass=gosaDepartment)', ['dn']); if ($ldap->count()) { $config->get_departments(); $config->make_idepartments(); $ui->reset_acl_cache(); } $this->handleForeignKeys($src_dn, $dst_dn); return TRUE; } function getRequiredAttributes() { $tmp = []; foreach ($this->attributesAccess as $attr) { if ($attr->isRequired()) { $tmp[] = $attr->getLdapName();
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
} } return $tmp; } function editing_group () { if ($this->editing_group == NULL) { if (isset($this->parent)) { $this->editing_group = (get_class($this->parent->getBaseObject()) == 'ogroup'); } else { return NULL; } } return $this->editing_group; } /*! \brief Indicates if this object is opened as read-only (because of locks) */ function readOnly() { return $this->read_only; } /*! \brief This function display the plugin and return the html code */ function execute () { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "execute"); /* Reset Lock message POST/GET check array, to prevent preg_match errors */ session::set('LOCK_VARS_TO_USE', []); session::set('LOCK_VARS_USED_GET', []); session::set('LOCK_VARS_USED_POST', []); session::set('LOCK_VARS_USED_REQUEST', []); $this->displayPlugin = TRUE; $this->header = ""; if (is_object($this->dialog)) { $dialogResult = $this->dialog->execute(); if ($dialogResult === FALSE) { $this->closeDialog(); } else { $this->header = $dialogResult; $this->displayPlugin = FALSE; return $this->header; } } if ($this->displayHeader) { /* Show tab dialog headers */ if ($this->parent !== NULL) { list($disabled, $buttonText, $text) = $this->getDisplayHeaderInfos(); $this->header = $this->show_header( $buttonText, $text, $this->is_account, $disabled, get_class($this).'_modify_state' ); if (!$this->is_account) { $this->displayPlugin = FALSE; return $this->header.$this->inheritanceDisplay(); } } elseif (!$this->is_account) { $plInfo = pluglist::pluginInfos(get_class($this)); $this->header = '<img alt="'._('Error').'" src="geticon.php?context=status&amp;icon=dialog-error&amp;size=16" align="middle"/>&nbsp;<b>'. msgPool::noValidExtension($plInfo['plShortName'])."</b>"; $this->header .= back_to_main(); $this->displayPlugin = FALSE;
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
return $this->header.$this->inheritanceDisplay(); } } $smarty = get_smarty(); $this->renderAttributes(FALSE); $smarty->assign("hiddenPostedInput", get_class($this)."_posted"); if (isset($this->focusedField)) { $smarty->assign("focusedField", $this->focusedField); unset($this->focusedField); } else { $smarty->assign("focusedField", key($this->attributesAccess)); } return $this->header.$smarty->fetch($this->templatePath); } public function getDisplayHeaderInfos() { $plInfo = pluglist::pluginInfos(get_class($this)); $disabled = $this->acl_skip_write(); if ($this->is_account) { $depends = []; if (isset($plInfo['plDepending'])) { foreach ($plInfo['plDepending'] as $plugin) { if (isset($this->parent->by_object[$plugin]) && $this->parent->by_object[$plugin]->is_account) { $disabled = TRUE; $dependPlInfos = pluglist::pluginInfos($plugin); $depends[] = $dependPlInfos['plShortName']; } } } $buttonText = msgPool::removeFeaturesButton($plInfo['plShortName']); $text = msgPool::featuresEnabled($plInfo['plShortName'], $depends); } else { $depends = []; $conflicts = []; if (isset($plInfo['plDepends'])) { foreach ($plInfo['plDepends'] as $plugin) { if (isset($this->parent->by_object[$plugin]) && !$this->parent->by_object[$plugin]->is_account) { $disabled = TRUE; $dependPlInfos = pluglist::pluginInfos($plugin); $depends[] = $dependPlInfos['plShortName']; } } } if (isset($plInfo['plConflicts'])) { foreach ($plInfo['plConflicts'] as $plugin) { if (isset($this->parent->by_object[$plugin]) && $this->parent->by_object[$plugin]->is_account) { $disabled = TRUE; $conflictPlInfos = pluglist::pluginInfos($plugin); $conflicts[] = $conflictPlInfos['plShortName']; } } } $buttonText = msgPool::addFeaturesButton($plInfo['plShortName']); $text = msgPool::featuresDisabled($plInfo['plShortName'], $depends, $conflicts); } return [$disabled,$buttonText,$text]; } /*! * \brief Show header message for tab dialogs * * \param string $button_text The button text *
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
* \param string $text The text * * \param boolean $plugin_enabled Is the plugin/tab activated * * \param boolean $button_disabled Is the button disabled * * \param string $name The html name of the input, defaults to modify_state */ function show_header($button_text, $text, $plugin_enabled, $button_disabled = FALSE, $name = 'modify_state') { if ($button_disabled || ((!$this->acl_is_createable() && !$plugin_enabled) || (!$this->acl_is_removeable() && $plugin_enabled))) { $state = 'disabled="disabled"'; } else { $state = ''; } $display = '<div width="100%"><p><b>'.$text.'</b><br/>'."\n"; $display .= '<input type="submit" value="'.$button_text.'" name="'.$name.'" '.$state.'></p></div><hr class="separator"/>'; return $display; } /*! \brief Check if logged in user have enough right to write this attribute value * * \param mixed $attr Attribute object or name (in this case it will be fetched from attributesAccess) */ function attrIsWriteable($attr) { if (!is_object($attr)) { $attr = $this->attributesAccess[$attr]; } if ($attr->getLdapName() == 'base') { if (!$this->acl_skip_write() && (!$this->initially_was_account || $this->acl_is_moveable() || $this->acl_is_removeable())) { return TRUE; } else { return FALSE; } } return $this->acl_is_writeable($attr->getAcl(), $this->acl_skip_write()); } function renderAttributes($readOnly = FALSE) { global $ui; $smarty = get_smarty(); if ($this->is_template) { $smarty->assign('template_cnACL', $ui->get_permissions($this->acl_base, $this->acl_category.'template', 'template_cn', $this->acl_skip_write())); } /* Handle rights to modify the base */ if (isset($this->attributesAccess['base'])) { if ($this->attrIsWriteable('base')) { $smarty->assign('baseACL', 'rw'); } else { $smarty->assign('baseACL', 'r'); } } $sections = []; foreach ($this->attributesInfo as $section => $sectionInfo) { $legend = $sectionInfo['name']; if (isset($sectionInfo['icon'])) { $legend = '<img '. 'src="'.htmlentities($sectionInfo['icon'], ENT_COMPAT, 'UTF-8').'" '. 'alt="" '. '/>'.$legend; } $smarty->assign("section", $legend); $smarty->assign("sectionId", $section); if (isset($sectionInfo['class'])) {
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
$smarty->assign("sectionClasses", ' '.join(' ', $sectionInfo['class'])); } else { $smarty->assign("sectionClasses", ''); } $attributes = []; foreach ($sectionInfo['attrs'] as $attr) { if ($attr->getAclInfo() !== FALSE) { // We assign ACLs so that attributes can use them in their template code $smarty->assign($attr->getAcl()."ACL", $this->aclGetPermissions($attr->getAcl(), NULL, $this->acl_skip_write())); } $attr->renderAttribute($attributes, $readOnly); } $smarty->assign("attributes", $attributes); // We fetch each section with the section template if (isset($sectionInfo['template'])) { $displaySection = $smarty->fetch($sectionInfo['template']); } else { $displaySection = $smarty->fetch(get_template_path('simpleplugin_section.tpl')); } $sections[$section] = $displaySection; } $smarty->assign("sections", $sections); } function inheritanceDisplay() { if (!$this->member_of_group) { return ""; } $class = get_class($this); $attrsWrapper = new stdClass(); $attrsWrapper->attrs = $this->group_attrs; $group = new $class($this->group_attrs['dn'], $attrsWrapper, $this->parent, $this->mainTab); $smarty = get_smarty(); $group->renderAttributes(TRUE); $smarty->assign("hiddenPostedInput", get_class($this)."_posted"); return "<h1>Inherited information:</h1><div></div>\n".$smarty->fetch($this->templatePath); } /*! \brief This function allows you to open a dialog * * \param mixed $dialog The dialog object */ function openDialog ($dialog) { $this->dialog = $dialog; } /*! \brief This function closes the dialog */ function closeDialog () { $this->dialog = NULL; } public function setNeedEditMode ($bool) { $this->needEditMode = $bool; } protected function acl_skip_write () { return ($this->needEditMode && !session::is_set('edit')); } /*! \brief Can we write the attribute */ function acl_is_writeable($attribute, $skipWrite = FALSE) {
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
return preg_match('/w/', $this->aclGetPermissions($attribute, NULL, $skipWrite)); } /*! * \brief Can we read the acl * * \param string $attribute */ function acl_is_readable($attribute) { return preg_match('/r/', $this->aclGetPermissions($attribute)); } /*! * \brief Can we create the object * * \param string $base Empty string */ function acl_is_createable($base = NULL) { return preg_match('/c/', $this->aclGetPermissions('0', $base)); } /*! * \brief Can we delete the object * * \param string $base Empty string */ function acl_is_removeable($base = NULL) { return preg_match('/d/', $this->aclGetPermissions('0', $base)); } /*! * \brief Can we move the object * * \param string $base Empty string */ function acl_is_moveable($base = NULL) { return preg_match('/m/', $this->aclGetPermissions('0', $base)); } /*! \brief Get the acl permissions for an attribute or the plugin itself */ function aclGetPermissions($attribute = '0', $base = NULL, $skipWrite = FALSE) { if (isset($this->parent) && isset($this->parent->ignoreAcls) && $this->parent->ignoreAcls) { return 'cdmr'.($skipWrite ? '' : 'w'); } $ui = get_userinfo(); $skipWrite |= $this->readOnly(); if ($base === NULL) { $base = $this->acl_base; } return $ui->get_permissions($base, $this->acl_category.get_class($this), $attribute, $skipWrite); } /*! \brief This function removes the object from LDAP */ function remove($fulldelete = FALSE) { if (!$this->initially_was_account) { return []; } if (!$fulldelete && !$this->acl_is_removeable()) { trigger_error('remove was called on a tab without enough ACL rights'); return []; }
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
$this->prepare_remove(); if ($this->is_template && (!defined('_OLD_TEMPLATES_') || !_OLD_TEMPLATES_)) { $this->attrs = $this->templateSaveAttrs(); $this->saved_attributes = []; } /* Pre hooks */ $errors = $this->pre_remove(); if (!empty($errors)) { return $errors; } $errors = $this->ldap_remove(); if (!empty($errors)) { return $errors; } $this->post_remove(); return []; } /* Remove FusionDirectory attributes */ protected function prepare_remove () { global $config; $this->attrs = []; if (!$this->mainTab) { /* include global link_info */ $ldap = $config->get_ldap_link(); /* Get current objectClasses in order to add the required ones */ $ldap->cat($this->dn); $tmp = $ldap->fetch (); $oc = []; if ($this->is_template) { if (isset($tmp['fdTemplateField'])) { foreach ($tmp['fdTemplateField'] as $tpl_field) { if (preg_match('/^objectClass:(.+)$/', $tpl_field, $m)) { $oc[] = $m[1]; } } } } else { if (isset($tmp['objectClass'])) { $oc = $tmp['objectClass']; unset($oc['count']); } } /* Remove objectClasses from entry */ $this->attrs['objectClass'] = array_remove_entries_ics($this->objectclasses, $oc); /* Unset attributes from entry */ foreach ($this->attributes as $val) { $this->attrs["$val"] = []; } } } protected function pre_remove () { if ($this->initially_was_account) { return $this->handle_pre_events('remove'); } } protected function ldap_remove () { global $config; $ldap = $config->get_ldap_link(); if ($this->mainTab) { $ldap->rmdir_recursive($this->dn);
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
} else { $this->cleanup(); $ldap->cd($this->dn); $ldap->modify($this->attrs); } $this->ldap_error = $ldap->get_error(); if ($ldap->success()) { return []; } else { return [msgPool::ldaperror($this->ldap_error, $this->dn, LDAP_MOD, get_class())]; } } protected function post_remove () { logging::log('remove', 'plugin/'.get_class($this), $this->dn, array_keys($this->attrs), $this->ldap_error); /* Optionally execute a command after we're done */ $errors = $this->handle_post_events('remove'); if (!empty($errors)) { msg_dialog::displayChecks($errors); } } /*! \brief This function handle $_POST informations */ function save_object () { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'save_object'); if ($this->displayHeader && isset($_POST[get_class($this).'_modify_state'])) { if ($this->is_account && $this->acl_is_removeable()) { $this->is_account = FALSE; } elseif (!$this->is_account && $this->acl_is_createable()) { $this->is_account = TRUE; } } if (isset($_POST[get_class($this).'_posted'])) { // If our form has been posted // A first pass that loads the post values foreach ($this->attributesInfo as $section => &$sectionInfo) { foreach ($sectionInfo['attrs'] as &$attr) { if ($this->attrIsWriteable($attr)) { // Each attribute know how to read its value from POST $attr->loadPostValue(); } } unset ($attrs); } unset($sectionInfo); // A second one that applies them. That allow complex stuff such as attribute disabling foreach ($this->attributesInfo as $section => &$sectionInfo) { foreach ($sectionInfo['attrs'] as &$attr) { if ($this->attrIsWriteable($attr)) { // Each attribute know how to read its value from POST $attr->applyPostValue(); } } unset ($attrs); } unset($sectionInfo); } } protected function prepareSavedAttributes() { /* Prepare saved attributes */ $this->saved_attributes = $this->attrs; foreach (array_keys($this->saved_attributes) as $index) { if (is_numeric($index)) {
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
unset($this->saved_attributes[$index]); continue; } if (!in_array_ics($index, $this->attributes) && strcasecmp('objectClass', $index)) { unset($this->saved_attributes[$index]); continue; } if (isset($this->saved_attributes[$index][0])) { if (!isset($this->saved_attributes[$index]['count'])) { $this->saved_attributes[$index]['count'] = count($this->saved_attributes[$index]); } if ($this->saved_attributes[$index]['count'] == 1) { $tmp = $this->saved_attributes[$index][0]; unset($this->saved_attributes[$index]); $this->saved_attributes[$index] = $tmp; continue; } } unset($this->saved_attributes[$index]['count']); } } /*! * \brief Remove attributes, empty arrays, arrays * single attributes that do not differ */ function cleanup() { foreach ($this->attrs as $index => $value) { /* Convert arrays with one element to non arrays, if the saved attributes are no array, too */ if (is_array($this->attrs[$index]) && (count($this->attrs[$index]) == 1) && isset($this->saved_attributes[$index]) && !is_array($this->saved_attributes[$index])) { $this->attrs[$index] = $this->attrs[$index][0]; } /* Remove emtpy arrays if they do not differ */ if (is_array($this->attrs[$index]) && (count($this->attrs[$index]) == 0) && !isset($this->saved_attributes[$index])) { unset ($this->attrs[$index]); continue; } /* Remove single attributes that do not differ */ if (!is_array($this->attrs[$index]) && isset($this->saved_attributes[$index]) && !is_array($this->saved_attributes[$index]) && ($this->attrs[$index] == $this->saved_attributes[$index])) { unset ($this->attrs[$index]); continue; } /* Remove arrays that do not differ */ if (is_array($this->attrs[$index]) && isset($this->saved_attributes[$index]) && is_array($this->saved_attributes[$index])) { if (!array_differs($this->attrs[$index], $this->saved_attributes[$index])) { unset ($this->attrs[$index]); continue; } } } }
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
function prepareNextCleanup() { /* Update saved attributes and ensure that next cleanups will be successful too */ foreach ($this->attrs as $name => $value) { $this->saved_attributes[$name] = $value; } } /*! \brief This function saves the object in the LDAP */ function save () { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, "save"); $errors = $this->prepare_save(); if (!empty($errors)) { return $errors; } if ($this->is_template && (!defined('_OLD_TEMPLATES_') || !_OLD_TEMPLATES_)) { $errors = templateHandling::checkFields($this->attrs); if (!empty($errors)) { return $errors; } $this->attrs = $this->templateSaveAttrs(); $this->saved_attributes = []; } $this->cleanup(); if (!$this->shouldSave()) { return []; /* Nothing to do here */ } /* Pre hooks */ $errors = $this->pre_save(); if (!empty($errors)) { return $errors; } /* LDAP save itself */ $errors = $this->ldap_save(); if (!empty($errors)) { return $errors; } $this->prepareNextCleanup(); /* Post hooks and logging */ $this->post_save(); return []; } protected function shouldSave() { if ($this->mainTab && !$this->initially_was_account) { return TRUE; } return !empty($this->attrs); } /* Used by prepare_save and template::apply */ public function mergeObjectClasses(array $oc) { return array_merge_unique($oc, $this->objectclasses); } protected function prepare_save () { global $config; /* prepare $this->attrs */ $ldap = $config->get_ldap_link(); $this->entryCSN = ''; /* Start with empty array */ $this->attrs = [];
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
/* Get current objectClasses in order to add the required ones */ $ldap->cat($this->dn, ['fdTemplateField', 'objectClass']); $tmp = $ldap->fetch(); $oc = []; if ($this->is_template) { if (isset($tmp['fdTemplateField'])) { foreach ($tmp['fdTemplateField'] as $tpl_field) { if (preg_match('/^objectClass:(.+)$/', $tpl_field, $m)) { $oc[] = $m[1]; } } } } else { if (isset($tmp['objectClass'])) { $oc = $tmp['objectClass']; unset($oc['count']); } } $this->attrs['objectClass'] = $this->mergeObjectClasses($oc); /* Fill attributes LDAP values into the attrs array */ foreach ($this->attributesInfo as $section => $sectionInfo) { foreach ($sectionInfo['attrs'] as $attr) { $attr->fillLdapValue($this->attrs); } } /* Some of them have post-filling hook */ foreach ($this->attributesInfo as $section => $sectionInfo) { foreach ($sectionInfo['attrs'] as $attr) { $attr->fillLdapValueHook($this->attrs); } } return []; } protected function pre_save () { if ($this->initially_was_account) { return $this->handle_pre_events('modify'); } else { return $this->handle_pre_events('add'); } } /* Returns an array with the errors or an empty array */ protected function ldap_save () { global $config; /* Check if this is a new entry ... add/modify */ $ldap = $config->get_ldap_link(); $ldap->cat($this->dn, ["objectClass"]); if ($this->mainTab && !$this->initially_was_account) { if ($ldap->count()) { return [sprintf(_('There is already an entry with the same dn : %s'), $this->dn)]; } $ldap->cd($config->current['BASE']); $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn)); $action = "add"; } else { if (!$ldap->count()) { return [sprintf(_('The entry %s is not existing'), $this->dn)]; } $action = "modify"; }
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
$ldap->cd($this->dn); $ldap->$action($this->attrs); $this->ldap_error = $ldap->get_error(); /* Check for errors */ if (!$ldap->success()) { return [msgPool::ldaperror($this->ldap_error, $this->dn, 0, get_class())]; } return []; } /*! \brief This function is called after LDAP save to do some post operations and logging * * This function calls hooks, update foreign keys and log modification */ protected function post_save() { /* Propagate and log the event */ if ($this->initially_was_account) { $errors = $this->handle_post_events('modify'); logging::log('modify', 'plugin/'.get_class($this), $this->dn, array_keys($this->attrs), $this->ldap_error); } else { $errors = $this->handle_post_events('add'); logging::log('create', 'plugin/'.get_class($this), $this->dn, array_keys($this->attrs), $this->ldap_error); } if (!empty($errors)) { msg_dialog::displayChecks($errors); } } /*! \brief Forward command execution requests * to the pre/post hook execution method. * * \param string $when must be PRE or POST * * \param string $mode add, remove or modify * * \param array $addAttrs */ protected function handle_hooks($when, $mode, array $addAttrs = []) { switch ($mode) { case 'add': return $this->callHook($when.'CREATE', $addAttrs); case 'modify': return $this->callHook($when.'MODIFY', $addAttrs); case 'remove': return $this->callHook($when.'REMOVE', $addAttrs); default: trigger_error(sprintf('Invalid %s event type given: "%s"! Valid types are: add, modify, remove.', strtolower($when), $mode)); break; } } /*! \brief Forward command execution requests * to the post hook execution method. */ function handle_post_events($mode, array $addAttrs = []) { /* Update foreign keys */ if ($mode == 'remove') { $this->handleForeignKeys($this->dn, NULL); } elseif ($mode == 'modify') { $this->handleForeignKeys(); } return $this->handle_hooks('POST', $mode, $addAttrs); }
1401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
/*! * \brief Forward command execution requests * to the pre hook execution method. */ function handle_pre_events($mode, array $addAttrs = []) { global $config; $this->ldap_error = ''; if ($this->mainTab && ($mode == 'remove')) { /* Store information if there was subobjects before deletion */ $ldap = $config->get_ldap_link(); $ldap->cd($this->dn); $ldap->search('(objectClass=*)', ['dn'], 'one'); $this->hadSubobjects = ($ldap->count() > 0); } return $this->handle_hooks('PRE', $mode, $addAttrs); } /*! * \brief Calls external hooks which are defined for this plugin (fusiondirectory.conf) * Replaces placeholder by class values of this plugin instance. * Allows to a add special replacements. */ function callHook($cmd, array $addAttrs = [], &$returnOutput = [], &$returnCode = NULL) { if ($this->is_template) { return []; } global $config; $commands = $config->searchHooks(get_class($this), $cmd); $messages = []; foreach ($commands as $command) { // Walk trough attributes list and add the plugins attributes. foreach ($this->attributes as $attr) { $addAttrs[$attr] = $this->$attr; } $ui = get_userinfo(); $addAttrs['callerDN'] = $ui->dn; $addAttrs['callerCN'] = $ui->cn; $addAttrs['callerUID'] = $ui->uid; $addAttrs['callerSN'] = $ui->sn; $addAttrs['callerGIVENNAME'] = $ui->givenName; $addAttrs['dn'] = $this->dn; $addAttrs['location'] = $config->current['NAME']; if (isset($this->parent->by_object)) { foreach ($this->parent->by_object as $object) { foreach ($object->attributes as $attr) { if (!isset($addAttrs[$attr])) { $addAttrs[$attr] = $object->$attr; } } } } if (!isset($addAttrs['base']) && isset($this->base)) { $addAttrs['base'] = $this->base; } $command = templateHandling::parseString($command, $addAttrs, 'escapeshellarg'); @DEBUG(DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Execute"); exec($command, $arr, $returnCode);
1471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
$returnOutput = $arr; if ($returnCode != 0) { $str = implode("\n", $arr); @DEBUG(DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Execution failed code: ".$returnCode); $message = msgPool::cmdexecfailed($cmd, $command, get_class($this)); if (!empty($str)) { $message .= "Result: ".$str; } $messages[] = $message; } elseif (is_array($arr)) { $str = implode("\n", $arr); @DEBUG(DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Result: ".$str); if (!empty($str) && $config->get_cfg_value("displayHookOutput", "FALSE") == "TRUE") { msg_dialog::display('['.get_class($this).' '.strtolower($cmd)."hook] $command", $str, INFO_DIALOG); } } } return $messages; } /*! \brief This function checks the attributes values and yell if something is wrong */ function check () { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->dn, 'check'); $messages = []; foreach ($this->attributesInfo as $sectionInfo) { foreach ($sectionInfo['attrs'] as $attr) { $error = $attr->check(); if (!empty($error)) { if (is_array($error)) { $messages = array_merge($messages, $error); } else { $messages[] = $error; } } } } $error = $this->callHook('CHECK', ['nbCheckErrors' => count($messages)], $returnOutput); if (!empty($error)) { $messages = array_merge($messages, $error); } if (!empty($returnOutput)) { $messages[] = join("\n", $returnOutput); } /* Check entryCSN */ if (!empty($this->entryCSN)) { $current_csn = getEntryCSN($this->dn); if (($current_csn != $this->entryCSN) && !empty($current_csn)) { $this->entryCSN = $current_csn; $messages[] = _('The object has changed since opened in FusionDirectory. All changes that may be done by others will get lost if you save this entry!'); } } return $messages; } function handleForeignKeys ($olddn = NULL, $newdn = NULL, $mode = 'move') { if (($olddn !== NULL) && ($olddn == $newdn)) { return; } if ($this->is_template) { return; } $this->browseForeignKeys(
1541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
'handle_'.$mode, $olddn, $newdn ); } function browseForeignKeys($mode, $param1 = NULL, $param2 = NULL) { global $config, $plist; $subobjects = FALSE; if (preg_match('/^handle_/', $mode)) { $olddn = $param1; $newdn = $param2; $classes = [get_class($this)]; if (($olddn != $newdn) && $this->mainTab) { if ($newdn === NULL) { $subobjects = $this->hadSubobjects; } else { $ldap = $config->get_ldap_link(); $ldap->cd($newdn); $ldap->search('(objectClass=*)', ['dn'], 'one'); $subobjects = ($ldap->count() > 0); } } } elseif ($mode == 'references') { $classes = array_keys($this->parent->by_object); } // We group by objectType concerned $foreignRefs = []; if ($subobjects) { $field = 'dn'; /* Special treatment for foreign keys on DN when moving an object * All references on DN are treated on subobjects */ foreach ($plist->dnForeignRefs as $ref) { $class = $ref[0]; $ofield = $ref[1]; $filter = $ref[2]; $filtersub = $ref[3]; if ($filtersub == '*') { if ($config->get_cfg_value('wildcardForeignKeys', 'TRUE') == 'TRUE') { $filtersub = $ofield.'=*'; } else { continue; } } if ($class == 'aclAssignment') { /* Special case: aclAssignment foreignKey is ignored on department types as it’s handled by the aclAssignment objectType */ $objectTypes = ['ACLASSIGNMENT']; } elseif (is_subclass_of($class, 'simpleService')) { $objectTypes = ['SERVER']; } else { $objectTypes = []; $cinfos = pluglist::pluginInfos($class); foreach ($cinfos['plObjectType'] as $key => $objectType) { if (!is_numeric($key)) { $objectType = $key; } if (preg_match('/^ogroup-/i', $objectType)) { $objectType = 'OGROUP'; } $objectTypes[] = strtoupper($objectType); } $objectTypes = array_unique($objectTypes); } foreach ($objectTypes as $objectType) { $oldvalue = $olddn; $newvalue = $newdn; $foreignRefs[$objectType]['refs'][$class][$ofield][$field] =
1611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
[ 'tab' => $classes[0], 'field' => $field, 'oldvalue' => $oldvalue, 'newvalue' => $newvalue, ]; $filter = templateHandling::parseString($filtersub, ['oldvalue' => $oldvalue, 'newvalue' => $newvalue], 'ldap_escape_f'); if (!preg_match('/^\(.*\)$/', $filter)) { $filter = '('.$filter.')'; } $foreignRefs[$objectType]['filters'][$filter] = $filter; } } } foreach ($classes as $tabclass) { $infos = pluglist::pluginInfos($tabclass); foreach ($infos['plForeignRefs'] as $field => $refs) { if (preg_match('/^handle_/', $mode)) { if (($newdn !== NULL) && ($field != 'dn') && ($mode == 'handle_move')) { // Move action, ignore other fields than dn continue; } elseif (($newdn === NULL) && ($olddn === NULL) && (($field == 'dn') || (!$this->attributeHaveChanged($field)))) { // Edit action, ignore dn changes or attributes which did not change continue; } // else = delete action, all fields are concerned, nothing to do here } foreach ($refs as $ref) { $class = $ref[0]; $ofield = $ref[1]; $filter = $ref[2]; $cinfos = pluglist::pluginInfos($class); if ($class == 'aclAssignment') { /* Special case: aclAssignment foreignKey is ignored on department types as it’s handled by the aclAssignment objectType */ $objectTypes = ['ACLASSIGNMENT']; } elseif (is_subclass_of($class, 'simpleService')) { $objectTypes = ['SERVER']; } else { $objectTypes = []; foreach ($cinfos['plObjectType'] as $key => $objectType) { if (!is_numeric($key)) { $objectType = $key; } if (preg_match('/^ogroup-/i', $objectType)) { $objectType = 'OGROUP'; } $objectTypes[] = $objectType; } $objectTypes = array_unique($objectTypes); } foreach ($objectTypes as $objectType) { if (preg_match('/^handle_/', $mode)) { if ($field == 'dn') { $oldvalue = $olddn; $newvalue = $newdn; } elseif (($olddn !== NULL) && ($newdn === NULL)) { $oldvalue = $this->attributeInitialValue($field); $newvalue = NULL; } else { $oldvalue = $this->attributeInitialValue($field); $newvalue = $this->attributeValue($field); } $foreignRefs[$objectType]['refs'][$class][$ofield][$field] = [ 'tab' => $tabclass, 'field' => $field, 'oldvalue' => $oldvalue, 'newvalue' => $newvalue, ]; $filter = templateHandling::parseString($filter, ['oldvalue' => $oldvalue, 'newvalue' => $newvalue], 'ldap_escape_f');
1681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
} elseif ($mode == 'references') { $foreignRefs[$objectType]['refs'][$class]['name'] = $cinfos['plShortName']; $foreignRefs[$objectType]['refs'][$class]['fields'][$ofield][$field] = [ 'tab' => $tabclass, 'field' => $field, 'tabname' => $this->parent->by_name[$tabclass], 'value' => $this->parent->by_object[$tabclass]->$field, ]; $filter = templateHandling::parseString($filter, ['oldvalue' => $this->parent->by_object[$tabclass]->$field], 'ldap_escape_f'); } if (!preg_match('/^\(.*\)$/', $filter)) { $filter = '('.$filter.')'; } $foreignRefs[$objectType]['filters'][$filter] = $filter; } } } } /* Back up POST content */ $SAVED_POST = $_POST; $refs = []; // For each concerned objectType foreach ($foreignRefs as $objectType => $tabRefs) { // Compute filter $filters = array_values($tabRefs['filters']); $filter = '(|'.join($filters).')'; // Search objects try { $objects = objects::ls($objectType, ['dn' => 'raw'], NULL, $filter); } catch (NonExistingObjectTypeException $e) { continue; } catch (EmptyFilterException $e) { continue; } // For each object of this type foreach (array_keys($objects) as $dn) { /* Avoid sending POST to opened objects */ $_POST = []; // Build the object $tabobject = objects::open($dn, $objectType); if (preg_match('/^handle_/', $mode)) { // For each tab concerned foreach ($tabRefs['refs'] as $tab => $fieldRefs) { // If the tab is activated on this object $pluginobject = $tabobject->getTabOrServiceObject($tab); if ($pluginobject !== FALSE) { // For each field foreach ($fieldRefs as $ofield => $fields) { foreach ($fields as $field) { // call plugin::foreignKeyUpdate(ldapname, oldvalue, newvalue, source) on the object $pluginobject->foreignKeyUpdate( $ofield, $field['oldvalue'], $field['newvalue'], [ 'CLASS' => $field['tab'], 'FIELD' => $field['field'], 'MODE' => preg_replace('/^handle_/', '', $mode), 'DN' => $this->dn, ] ); } } $pluginobject->save_object(); } } $errors = $tabobject->save();
1751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820
msg_dialog::displayChecks($errors); } elseif ($mode == 'references') { // For each tab concerned foreach ($tabRefs['refs'] as $tab => $tab_infos) { // If the tab is activated on this object $pluginobject = $tabobject->getTabOrServiceObject($tab); if ($pluginobject !== FALSE) { // For each field foreach ($tab_infos['fields'] as $ofield => $fields) { foreach ($fields as $field) { if ($pluginobject->foreignKeyCheck( $ofield, $field['value'], [ 'CLASS' => $field['tab'], 'FIELD' => $field['field'], 'DN' => $this->dn, ] )) { if (!isset($refs[$dn])) { $refs[$dn] = [ 'link' => '', 'tabs' => [], ]; try { $refs[$dn]['link'] = objects::link($dn, $objectType); } catch (FusionDirectoryException $e) { trigger_error("Could not create link to $dn: ".$e->getMessage()); $refs[$dn]['link'] = $dn; } } if (!isset($refs[$dn]['tabs'][$tab])) { $refs[$dn]['tabs'][$tab] = [ 'link' => '', 'fields' => [], ]; try { if (is_subclass_of($tab, 'simpleService')) { $refs[$dn]['tabs'][$tab]['link'] = objects::link($dn, $objectType, "service_$tab", sprintf(_('Service "%s"'), $tab_infos['name'])); } else { $refs[$dn]['tabs'][$tab]['link'] = objects::link($dn, $objectType, "tab_$tab", sprintf(_('Tab "%s"'), $tab_infos['name'])); } } catch (FusionDirectoryException $e) { trigger_error("Could not create link to $dn $tab: ".$e->getMessage()); $refs[$dn]['tabs'][$tab]['link'] = $tab; } } $refs[$dn]['tabs'][$tab]['fields'][$ofield] = $field; } } } } } } } } /* Restore POST */ $_POST = $SAVED_POST; if ($mode == 'references') { return $refs; } } /*! * \brief Create unique DN * * \param string $attribute * * \param string $base */
1821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890
function create_unique_dn($attribute, $base) { global $config; $ldap = $config->get_ldap_link(); $base = preg_replace('/^,*/', '', $base); /* Try to use plain entry first */ $dn = $attribute.'='.ldap_escape_dn($this->$attribute).','.$base; if (($dn == $this->orig_dn) || !$ldap->dn_exists($dn)) { return $dn; } /* Build DN with multiple attributes */ $usableAttributes = []; foreach ($this->attributes as $attr) { if (($attr != $attribute) && is_scalar($this->$attr) && ($this->$attr != '')) { $usableAttributes[] = (string)$attr; } } for ($i = 1; $i < count($usableAttributes); $i++) { foreach (new Combinations($usableAttributes, $i) as $attrs) { $dn = $attribute.'='.ldap_escape_dn($this->$attribute); foreach ($attrs as $attr) { $dn .= '+'.$attr.'='.ldap_escape_dn($this->$attr); } $dn .= ','.$base; if (($dn == $this->orig_dn) || !$ldap->dn_exists($dn)) { return $dn; } } } /* None found */ throw new FusionDirectoryException(_('Failed to create a unique DN')); } /* * \brief Adapt from template, using 'dn' * * \param string $dn The DN * * \param array $skip A new array */ function adapt_from_template($attrs, $skip = []) { $this->attrs = $attrs; /* Walk through attributes */ foreach ($this->attributesAccess as $ldapName => &$attr) { /* Skip the ones in skip list */ if (in_array($ldapName, $skip)) { continue; } /* Load values */ $attr->loadValue($this->attrs); } unset($attr); /* Is Account? */ $this->is_account = $this->is_this_account($this->attrs); } /*! * \brief This function is called on the copied object to set its dn to where it will be saved */ function resetCopyInfos() { $this->dn = 'new'; $this->orig_dn = $this->dn;
1891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960
$this->saved_attributes = []; $this->initially_was_account = FALSE; } protected function attributeHaveChanged($field) { return $this->attributesAccess[$field]->hasChanged(); } protected function attributeValue($field) { return $this->attributesAccess[$field]->getValue(); } protected function attributeInitialValue($field) { return $this->attributesAccess[$field]->getInitialValue(); } function foreignKeyUpdate ($field, $oldvalue, $newvalue, $source) { if (!isset($source['MODE'])) { $source['MODE'] = 'move'; } $this->attributesAccess[$field]->foreignKeyUpdate($oldvalue, $newvalue, $source); } /* * Source is an array like this: * array( * 'CLASS' => class, * 'FIELD' => field, * 'DN' => dn, * 'MODE' => mode * ) * mode being either 'copy' or 'move', defaults to 'move' */ function foreignKeyCheck ($field, $value, $source) { return $this->attributesAccess[$field]->foreignKeyCheck($value, $source); } function deserializeValues($values, $checkAcl = TRUE) { foreach ($values as $name => $value) { if (isset($this->attributesAccess[$name])) { if (!$checkAcl || $this->attrIsWriteable($name)) { $error = $this->attributesAccess[$name]->deserializeValue($value); if (!empty($error)) { return $error; } } else { return msgPool::permModify($this->dn, $name); } } else { return sprintf(_('Unknown field "%s"'), $name); } } return TRUE; } /* Returns TRUE if this attribute should be asked in the creation by template dialog */ function showInTemplate($attr, $templateAttrs) { if (isset($templateAttrs[$attr])) { return FALSE; } return TRUE; }
1961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030
function is_modal_dialog() { return (isset($this->dialog) && $this->dialog); } /*! * \brief Return plugin informations for acl handling * * \return an array */ static function plInfo() { return []; } /*! \brief This function generate the needed ACLs for a given attribtues array * * \param array $attributesInfo the attribute array */ static function generatePlProvidedAcls ($attributesInfo) { $plProvidedAcls = []; foreach ($attributesInfo as $sectionInfo) { foreach ($sectionInfo['attrs'] as $attr) { $aclInfo = $attr->getAclInfo(); if ($aclInfo !== FALSE) { $plProvidedAcls[$aclInfo['name']] = $aclInfo['desc']; } } } return $plProvidedAcls; } /*! \brief This function is the needed main.inc for plugins that are not used inside a management class * * \param array $classname the class name to read plInfo from. (plIcon, plShortname and plCategory are gonna be used) * * \param string $entry_dn the dn of the object to show/edit * * \param boolean $tabs TRUE to use tabs, FALSE to show directly the plugin class * * \param boolean $edit_mode wether or not this plugin can be edited * * \param string $objectType The objectType to use (will be taken in the plInfo if FALSE) * */ static function mainInc ($classname, $entry_dn, $tabs = FALSE, $edit_mode = TRUE, $objectType = FALSE) { global $remove_lock, $cleanup, $display, $config, $plug, $ui; $plInfo = pluglist::pluginInfos($classname); $plIcon = (isset($plInfo['plIcon']) ? $plInfo['plIcon'] : 'plugin.png'); $plHeadline = $plInfo['plTitle']; if ($objectType === FALSE) { $key = key($plInfo['plObjectType']); if (is_numeric($key)) { $key = $plInfo['plObjectType'][$key]; } $objectType = $key; } $plCategory = (isset($plInfo['plCategory']) ? $plInfo['plCategory'] : ['user']); $key = key($plCategory); if (is_numeric($key)) { $plCategory = $plCategory[$key]; } else { $plCategory = $key; } $lock_msg = "";
2031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100
if ($edit_mode) { /* Remove locks created by this plugin */ if ($remove_lock || (isset($_POST['edit_cancel']) && session::is_set('edit'))) { if (session::is_set($classname)) { del_lock($entry_dn); } } } /* Remove this plugin from session */ if ($cleanup) { session::un_set($classname); session::un_set('edit'); } else { /* Reset requested? */ if ($edit_mode && isset($_POST['edit_cancel'])) { session::un_set($classname); session::un_set('edit'); } /* Create tab object on demand */ if (!session::is_set($classname) || (isset($_GET['reset']) && $_GET['reset'] == 1)) { try { $tabObject = objects::open($entry_dn, $objectType); } catch (NonExistingLdapNodeException $e) { $tabObject = objects::open('new', $objectType); } if ($edit_mode) { $tabObject->setNeedEditMode(TRUE); } if (!$tabs) { $tabObject->current = $classname; } if (($entry_dn != '') && ($entry_dn != 'new')) { $tabObject->set_acl_base($entry_dn); } else { $tabObject->set_acl_base($config->current['BASE']); } session::set($classname, $tabObject); } $tabObject = session::get($classname); /* save changes back to object */ if (!$edit_mode || session::is_set('edit')) { $tabObject->save_object(); } if ($edit_mode) { /* Enter edit mode? */ if ((isset($_POST['edit'])) && (!session::is_set('edit'))) { /* Check locking */ if ($locks = get_locks($entry_dn)) { session::set('back_plugin', $plug); session::set('LOCK_VARS_TO_USE', ["/^edit$/", "/^plug$/"]); $lock_msg = gen_locked_message($locks, $entry_dn); } else { /* Lock the current entry */ add_lock($entry_dn, $ui->dn); session::set('edit', TRUE); } } /* save changes to LDAP and disable edit mode */ $info = ""; if (isset($_POST['edit_finish'])) { /* Perform checks */ $message = $tabObject->save(); /* No errors, save object */ if (count($message) == 0) {
2101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164
del_lock($entry_dn); session::un_set('edit'); /* Remove from session */ session::un_set($classname); } else { /* Errors found, show message */ msg_dialog::displayChecks($message); } } } else { $info = ""; } /* Execute formular */ if ($edit_mode && $lock_msg) { $display = $lock_msg; } else { if ($tabs) { $display .= $tabObject->execute(); } else { $display .= $tabObject->by_object[$classname]->execute(); } } /* Store changes in session */ if (!$edit_mode || session::is_set('edit')) { session::set($classname, $tabObject); } /* Show page footer depending on the mode */ $info = $entry_dn.'&nbsp;'; if ($edit_mode && (!$tabObject->dialogOpened()) && empty($lock_msg)) { $display .= '<p class="plugbottom">'; /* Are we in edit mode? */ if (session::is_set('edit')) { $display .= '<input type="submit" name="edit_finish" style="width:80px" value="'.msgPool::okButton().'"/>'."\n"; $display .= '&nbsp;'; $display .= '<input type="submit" name="edit_cancel" value="'.msgPool::cancelButton().'"/>'."\n"; } else { /* Only display edit button if there is at least one attribute editable */ if (preg_match('/r/', $ui->get_permissions($entry_dn, $plCategory.'/'.$tabObject->current))) { $info .= '<div style="float:left;" class="optional"><img class="center" alt="information" '. 'src="geticon.php?context=status&amp;icon=dialog-information&amp;size=16"> '. msgPool::clickEditToChange().'</div>'; $display .= '<input type="submit" name="edit" value="'.msgPool::editButton().'"/>'."\n"; } $display .= '<input type="hidden" name="ignore"/>'."\n"; } $display .= "</p>\n"; } /* Page header */ if (!preg_match('/^geticon/', $plIcon)) { $plIcon = get_template_path($plIcon); } $display = print_header($plIcon, $plHeadline, $info).$display; } } } ?>