From 00122031cae6930074bfb79b1d0210a490fca5bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come.chilliet@fusiondirectory.org>
Date: Tue, 31 Mar 2020 15:48:14 +0200
Subject: [PATCH] :ambulance: fix(ldap) Remove numeric indexes and count key
 from LDAP array

This avoids problems with templates not behaving like LDAP data.
I tried to use the option in all cases where the array is stored for
 futur use, and of course especially for simplePlugin.

issue #6080
---
 include/class_ldap.inc                               | 10 +++++++++-
 include/class_templateHandling.inc                   |  6 ++++--
 include/class_userinfo.inc                           |  2 +-
 .../management/snapshot/class_SnapshotHandler.inc    |  8 ++++----
 include/password-methods/class_passwordMethod.inc    |  2 +-
 .../simpleplugin/attributes/class_SetAttribute.inc   |  2 +-
 include/simpleplugin/class_dialogAttributes.inc      |  4 ++--
 include/simpleplugin/class_simplePlugin.inc          |  6 +++---
 plugins/admin/groups/class_groupManagement.inc       |  2 +-
 plugins/personal/generic/class_user.inc              |  4 ++--
 setup/class_setupStepMigrate.inc                     | 12 ++++++------
 11 files changed, 34 insertions(+), 24 deletions(-)

diff --git a/include/class_ldap.inc b/include/class_ldap.inc
index 1ac53137d..01626af72 100644
--- a/include/class_ldap.inc
+++ b/include/class_ldap.inc
@@ -483,8 +483,9 @@ class LDAP
    * \brief Fetch
    *
    * \param integer $srp
+   * \param bool    $cleanUpNumericIndices whether to remove numeric indices and "count" index at top level ("count" index in each attribute value is kept)
    */
-  function fetch ($srp)
+  function fetch ($srp, bool $cleanUpNumericIndices = FALSE)
   {
     $att = [];
     if ($this->hascon) {
@@ -502,6 +503,13 @@ class LDAP
         if ($this->re[$srp]) {
           $att        = @ldap_get_attributes($this->cid, $this->re[$srp]);
           $att['dn']  = trim(@ldap_get_dn($this->cid, $this->re[$srp]));
+          if ($cleanUpNumericIndices && isset($att['count'])) {
+            for ($i = 0; $i < $att['count']; ++$i) {
+              /* Remove numeric keys */
+              unset($att[$i]);
+            }
+            unset($att['count']);
+          }
         }
         $this->error = @ldap_error($this->cid);
         if (!isset($att)) {
diff --git a/include/class_templateHandling.inc b/include/class_templateHandling.inc
index 4fe0c6928..2d8eb2c22 100644
--- a/include/class_templateHandling.inc
+++ b/include/class_templateHandling.inc
@@ -34,7 +34,7 @@ class templateHandling
 
     $ldap = $config->get_ldap_link();
     $ldap->cat($dn);
-    $attrs    = $ldap->fetch();
+    $attrs    = $ldap->fetch(TRUE);
     $attrs    = static::fieldsFromLDAP($attrs);
     list($depends, $errors) = static::attributesDependencies($attrs);
     msg_dialog::displayChecks($errors);
@@ -50,7 +50,9 @@ class templateHandling
       unset($template_attrs['fdTemplateField']['count']);
       sort($template_attrs['fdTemplateField']);
       foreach ($template_attrs['fdTemplateField'] as $field) {
-        preg_match('/^([^:]+):(.*)$/s', $field, $m);
+        if (!preg_match('/^([^:]+):(.*)$/s', $field, $m)) {
+          throw new FusionDirectoryException('Template field does not match format');
+        }
         if (isset($attrs[$m[1]])) {
           $attrs[$m[1]][] = $m[2];
           $attrs[$m[1]]['count']++;
diff --git a/include/class_userinfo.inc b/include/class_userinfo.inc
index db1ec50b4..2f07fe704 100644
--- a/include/class_userinfo.inc
+++ b/include/class_userinfo.inc
@@ -86,7 +86,7 @@ class userinfo
     global $config;
     $ldap = $config->get_ldap_link();
     $ldap->cat($this->dn, ['*']);
-    $attrs = $ldap->fetch();
+    $attrs = $ldap->fetch(TRUE);
 
     $this->uid = $attrs['uid'][0];
 
diff --git a/include/management/snapshot/class_SnapshotHandler.inc b/include/management/snapshot/class_SnapshotHandler.inc
index ef1ac22b6..3ebfaa761 100644
--- a/include/management/snapshot/class_SnapshotHandler.inc
+++ b/include/management/snapshot/class_SnapshotHandler.inc
@@ -166,7 +166,7 @@ class SnapshotHandler
 
     /* Put results into a list and add description if missing */
     $objects = [];
-    while ($entry = $ldap->fetch()) {
+    while ($entry = $ldap->fetch(TRUE)) {
       if (!isset($entry['description'][0])) {
         $entry['description'][0]  = "";
       }
@@ -310,7 +310,7 @@ class SnapshotHandler
     );
 
     /* Put results into a list and add description if missing */
-    while ($entry = $ldap->fetch()) {
+    while ($entry = $ldap->fetch(TRUE)) {
       if (!isset($entry['description'][0])) {
         $entry['description'][0]  = "";
       }
@@ -344,7 +344,7 @@ class SnapshotHandler
       ['gosaSnapshotTimestamp','gosaSnapshotDN','description','fdSnapshotObjectType'],
       'one'
     );
-    while ($entry = $ldap->fetch()) {
+    while ($entry = $ldap->fetch(TRUE)) {
       $chk = str_replace($new_base, "", $entry['dn']);
       if (preg_match("/,ou=/", $chk)) {
         continue;
@@ -383,7 +383,7 @@ class SnapshotHandler
     $ldap = $config->get_ldap_link();
 
     /* Get the snapshot */
-    $ldap->cat($dn, ['gosaSnapshotData','gosaSnapshotDN','fdSnapshotObjectType'], '(gosaSnapshotData=*)');
+    $ldap->cat($dn, ['gosaSnapshotData'], '(gosaSnapshotData=*)');
     if ($attrs = $ldap->fetch()) {
       /* Prepare import string */
       $data = gzuncompress($attrs['gosaSnapshotData'][0]);
diff --git a/include/password-methods/class_passwordMethod.inc b/include/password-methods/class_passwordMethod.inc
index 42abc4a33..95f961922 100644
--- a/include/password-methods/class_passwordMethod.inc
+++ b/include/password-methods/class_passwordMethod.inc
@@ -106,7 +106,7 @@ abstract class passwordMethod
     if (!empty($dn)) {
       $ldap = $config->get_ldap_link();
       $ldap->cd($config->current['BASE']);
-      $ldap->cat($dn);
+      $ldap->cat($dn, ['userPassword']);
       $attrs = $ldap->fetch();
       if (isset($attrs['userPassword'][0])) {
         $pwd = $attrs['userPassword'][0];
diff --git a/include/simpleplugin/attributes/class_SetAttribute.inc b/include/simpleplugin/attributes/class_SetAttribute.inc
index 781f8d29a..d79d36654 100644
--- a/include/simpleplugin/attributes/class_SetAttribute.inc
+++ b/include/simpleplugin/attributes/class_SetAttribute.inc
@@ -745,7 +745,7 @@ class SubNodesAttribute extends OrderedArrayAttribute
       $ldap->cd($attrs['dn']);
       $ldap->search('objectClass='.$this->objectClass, ['*'], 'one');
       $this->value = [];
-      while ($subattrs = $ldap->fetch()) {
+      while ($subattrs = $ldap->fetch(TRUE)) {
         $this->attribute->resetToDefault();
         foreach ($this->attribute->attributes as &$attribute) {
           $attribute->loadAttrValue($subattrs);
diff --git a/include/simpleplugin/class_dialogAttributes.inc b/include/simpleplugin/class_dialogAttributes.inc
index bf2c59675..3a46a766d 100644
--- a/include/simpleplugin/class_dialogAttributes.inc
+++ b/include/simpleplugin/class_dialogAttributes.inc
@@ -394,7 +394,7 @@ class GenericDialogAttribute extends DialogAttribute
       $ldap->cd($config->current['BASE']);
       $ldap->search('('.$this->store_attr.'='.ldap_escape_f($value).')', $this->ldapAttributesToGet());
     }
-    $attrs = $ldap->fetch();
+    $attrs = $ldap->fetch(TRUE);
     if (empty($attrs) && $this->isTemplate()) {
       $this->fillDisplayValueFrom($i, NULL);
     } else {
@@ -777,7 +777,7 @@ class ObjectAttribute extends DialogButtonAttribute
       if ($dn != '') {
         $ldap = $config->get_ldap_link();
         $ldap->cat($dn, [$this->displayAttr]);
-        if ($attrs = $ldap->fetch()) {
+        if ($attrs = $ldap->fetch(TRUE)) {
           $this->handleDialogResult($dn, $attrs);
         } else {
           $this->buttonText = NULL;
diff --git a/include/simpleplugin/class_simplePlugin.inc b/include/simpleplugin/class_simplePlugin.inc
index 2e07c1660..333eb8f1b 100644
--- a/include/simpleplugin/class_simplePlugin.inc
+++ b/include/simpleplugin/class_simplePlugin.inc
@@ -232,7 +232,7 @@ class simplePlugin implements SimpleTab
         /* From LDAP */
         $ldap = $config->get_ldap_link();
         $ldap->cat($this->dn);
-        $this->attrs = $ldap->fetch();
+        $this->attrs = $ldap->fetch(TRUE);
         if (empty($this->attrs)) {
           throw new NonExistingLdapNodeException('Could not open dn '.$this->dn);
         }
@@ -388,7 +388,7 @@ class simplePlugin implements SimpleTab
     global $config;
     $ldap = $config->get_ldap_link();
     $ldap->cat($this->dn);
-    $template_attrs = $ldap->fetch();
+    $template_attrs = $ldap->fetch(TRUE);
     if (!$template_attrs) {
       if (!$this->mainTab) {
         trigger_error('It seems main tab has not been saved.');
@@ -1055,7 +1055,7 @@ class simplePlugin implements SimpleTab
       $ldap = $config->get_ldap_link();
 
       /* Get current objectClasses in order to add the required ones */
-      $ldap->cat($this->dn);
+      $ldap->cat($this->dn, ['fdTemplateField','objectClass']);
       $tmp  = $ldap->fetch();
       $oc   = [];
       if ($this->is_template) {
diff --git a/plugins/admin/groups/class_groupManagement.inc b/plugins/admin/groups/class_groupManagement.inc
index f35fd40ba..34a9c8b37 100644
--- a/plugins/admin/groups/class_groupManagement.inc
+++ b/plugins/admin/groups/class_groupManagement.inc
@@ -126,7 +126,7 @@ class groupManagement extends management
       $obj = $this->listing->getEntry($dn);
       if (isset($obj['member'])) {
         foreach ($obj['member'] as $member) {
-          $ldap->cat($member);
+          $ldap->cat($member, ['macAddress']);
           if ($attrs = $ldap->fetch()) {
             if (isset($attrs['macAddress'][0])) {
               $mac[] = $attrs['macAddress'][0];
diff --git a/plugins/personal/generic/class_user.inc b/plugins/personal/generic/class_user.inc
index b6915a3a3..3ddbaf96e 100644
--- a/plugins/personal/generic/class_user.inc
+++ b/plugins/personal/generic/class_user.inc
@@ -414,7 +414,7 @@ class user extends simplePlugin
 
     $ldap = $config->get_ldap_link();
     $ldap->cat($userdn, ['pwdPolicySubentry', 'pwdHistory', 'pwdChangedTime', 'userPassword']);
-    $attrs = $ldap->fetch();
+    $attrs = $ldap->fetch(TRUE);
     $ppolicydn = '';
     if (isset($attrs['pwdPolicySubentry'][0])) {
       $ppolicydn = $attrs['pwdPolicySubentry'][0];
@@ -428,7 +428,7 @@ class user extends simplePlugin
     $policy = NULL;
     if (!empty($ppolicydn)) {
       $ldap->cat($ppolicydn, ['pwdAllowUserChange', 'pwdMinLength', 'pwdMinAge', 'pwdSafeModify', 'pwdExpireWarning', 'pwdMaxAge']);
-      $policy = $ldap->fetch();
+      $policy = $ldap->fetch(TRUE);
       if (!$policy) {
         throw new NonExistingLdapNodeException(sprintf(_('Ppolicy "%s" could not be found in the LDAP!'), $ppolicydn));
       }
diff --git a/setup/class_setupStepMigrate.inc b/setup/class_setupStepMigrate.inc
index 8897217b6..111f90455 100644
--- a/setup/class_setupStepMigrate.inc
+++ b/setup/class_setupStepMigrate.inc
@@ -345,7 +345,7 @@ class setupStepMigrate extends setupStep
       );
     }
 
-    $attrs = $ldap->fetch();
+    $attrs = $ldap->fetch(TRUE);
 
     /* Root object doesn't exists */
     if (!in_array("gosaDepartment", $attrs['objectClass'])) {
@@ -570,7 +570,7 @@ class setupStepMigrate extends setupStep
     $sizeLimitHit   = $ldap->hitSizeLimit();
     $accountsCount  = $ldap->count();
 
-    while ($attrs = $ldap->fetch()) {
+    while ($attrs = $ldap->fetch(TRUE)) {
       $base = preg_replace('/^[^,]+,/', '', $attrs['dn']);
 
       /* Build groupid depending on base and objectClasses */
@@ -689,7 +689,7 @@ class setupStepMigrate extends setupStep
         foreach ($objects as &$object) {
           /* Get old objectClasses */
           $ldap->cat($object['dn'], array_merge(['objectClass'], array_keys($mandatory)));
-          $attrs = $ldap->fetch();
+          $attrs = $ldap->fetch(TRUE);
 
           /* Create new objectClass array */
           $new_attrs  = [];
@@ -744,7 +744,7 @@ class setupStepMigrate extends setupStep
     /* Establish ldap connection */
     $ldap = $config->get_ldap_link();
     $ldap->cd($config->current['BASE']);
-    $res = $ldap->cat($config->current['BASE']);
+    $res = $ldap->cat($config->current['BASE'], ['gosaAclEntry']);
 
     if (!$res) {
       throw new CheckFailedException(
@@ -1079,7 +1079,7 @@ class setupStepMigrate extends setupStep
         }
       }
 
-      while ($attrs = $ldap->fetch()) {
+      while ($attrs = $ldap->fetch(TRUE)) {
         $object_base  = preg_replace('/^[^,]+,'.preg_quote($objects_ou, '/').'/i', '', $attrs['dn'], 1, $pregCount);
         $base         = preg_replace('/^[^,]+,/', '', $attrs['dn']);
 
@@ -1330,7 +1330,7 @@ class setupStepMigrate extends setupStep
     }
     $sizeLimitHit = FALSE;
 
-    while ($attrs = $ldap->fetch()) {
+    while ($attrs = $ldap->fetch(TRUE)) {
       foreach ($skip_dns as $skip_dn) {
         /* Filter out FusionDirectory internal departments */
         if (preg_match($skip_dn, $attrs['dn'])) {
-- 
GitLab