From 07e29613873d30f99c94b5cb452389e1f055c0c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=B4me=20Chilliet?= <come.chilliet@fusiondirectory.org>
Date: Thu, 17 Jun 2021 11:18:53 +0200
Subject: [PATCH] :sparkles: feat(core) Check that max_input_vars is not
 reached by management classes.

This is easy to check as management classes respect the size limit
 option.

issue #6169
---
 include/class_ldapSizeLimit.inc               | 30 +++++++++++++++++--
 .../management/class_managementListing.inc    |  9 ++++++
 plugins/config/class_configInLdap.inc         | 13 ++++++++
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/include/class_ldapSizeLimit.inc b/include/class_ldapSizeLimit.inc
index 2badc90e0..20c8e1922 100644
--- a/include/class_ldapSizeLimit.inc
+++ b/include/class_ldapSizeLimit.inc
@@ -71,8 +71,12 @@ class ldapSizeLimit
       switch ($_POST['action']) {
         case 'newlimit':
           if (isset($_POST['new_limit']) && tests::is_id($_POST['new_limit'])) {
-            $this->sizeLimit  = intval($_POST['new_limit']);
-            $this->ignore     = FALSE;
+            if (($error = static::checkMaxInputVars($_POST['new_limit'])) !== FALSE) {
+              $error->display();
+            } else {
+              $this->sizeLimit  = intval($_POST['new_limit']);
+              $this->ignore     = FALSE;
+            }
           }
           break;
         case 'ignore':
@@ -132,4 +136,26 @@ class ldapSizeLimit
     }
     return '';
   }
+
+  /**
+   * Checks if a new limit or a number of entries is too high regarding to max_input_vars.
+   *
+   * If there are more items in $_POST than max_input_vars, PHP will discard some of them and will cause a CSRF error.
+   */
+  static public function checkMaxInputVars (int $newLimit, string $messageTemplate = NULL)
+  {
+    $maxInputVars = ini_get('max_input_vars');
+
+    if (($maxInputVars != '') && (($newLimit + 10) >= intval($maxInputVars))) {
+      return new FusionDirectoryError(
+        htmlescape(sprintf(
+          $messageTemplate ?? _('Limit %d is greater than or too close to configured max_input_vars PHP ini setting of %d. Please change max_input_vars ini setting to a higher value if you wish to set the limit higher.'),
+          $newLimit,
+          $maxInputVars
+        ))
+      );
+    }
+
+    return FALSE;
+  }
 }
diff --git a/include/management/class_managementListing.inc b/include/management/class_managementListing.inc
index 4bbe62d5a..a0b97a932 100644
--- a/include/management/class_managementListing.inc
+++ b/include/management/class_managementListing.inc
@@ -227,6 +227,15 @@ class managementListing
       $smarty->assign('objectCounts', $types);
     }
 
+    /* If the user ignored the sizelimit warning he may get more entries than what PHP can handle */
+    $error = ldapSizeLimit::checkMaxInputVars(
+      count($this->entries),
+      _('The number of listed entries (%d) is greater than or too close to configured max_input_vars PHP ini setting (%d). Please change max_input_vars ini setting to a higher value.')
+    );
+    if ($error !== FALSE) {
+      $error->display();
+    }
+
     return $smarty->fetch(get_template_path('management/list.tpl'));
   }
 
diff --git a/plugins/config/class_configInLdap.inc b/plugins/config/class_configInLdap.inc
index 69e9dc581..6e89b975a 100644
--- a/plugins/config/class_configInLdap.inc
+++ b/plugins/config/class_configInLdap.inc
@@ -553,6 +553,19 @@ class configInLdap extends simplePlugin
         htmlescape(sprintf(_('It seems the selected language "%s" is not installed on the system. Please install it or select an other one.'), $this->fdLanguage))
       );
     }
+
+    if (($this->fdLdapSizeLimit !== '') && ($this->fdLdapSizeLimit > 0)) {
+      $error = ldapSizeLimit::checkMaxInputVars($this->fdLdapSizeLimit);
+      if ($error !== FALSE) {
+        $messages[] = new SimplePluginCheckError(
+          $this->attributesAccess['fdLdapSizeLimit'],
+          $error->getHtmlMessage(),
+          $error->getCode(),
+          $error
+        );
+      }
+    }
+
     return $messages;
   }
 
-- 
GitLab