diff --git a/library/Icinga/Protocol/Ldap/LdapConnection.php b/library/Icinga/Protocol/Ldap/LdapConnection.php index 18101d2e2..9dc962407 100644 --- a/library/Icinga/Protocol/Ldap/LdapConnection.php +++ b/library/Icinga/Protocol/Ldap/LdapConnection.php @@ -889,13 +889,17 @@ class LdapConnection implements Selectable, Inspectable } } + $legacyControlHandling = version_compare(PHP_VERSION, '7.3.0') < 0; + $count = 0; $cookie = ''; $entries = array(); do { - // Do not request the pagination control as a critical extension, as we want the - // server to return results even if the paged search request cannot be satisfied - ldap_control_paged_result($ds, $pageSize, false, $cookie); + if ($legacyControlHandling) { + // Do not request the pagination control as a critical extension, as we want the + // server to return results even if the paged search request cannot be satisfied + ldap_control_paged_result($ds, $pageSize, false, $cookie); + } if ($serverSorting && $query->hasOrder()) { ldap_set_option($ds, LDAP_OPT_SERVER_CONTROLS, array( @@ -910,7 +914,10 @@ class LdapConnection implements Selectable, Inspectable $query, array_values($fields), 0, - ($serverSorting || ! $query->hasOrder()) && $limit ? $offset + $limit : 0 + ($serverSorting || ! $query->hasOrder()) && $limit ? $offset + $limit : 0, + 0, + LDAP_DEREF_NEVER, + $legacyControlHandling ? null : $pageSize ); if ($results === false) { if (ldap_errno($ds) === self::LDAP_NO_SUCH_OBJECT) { @@ -976,7 +983,7 @@ class LdapConnection implements Selectable, Inspectable && ($entry = ldap_next_entry($ds, $entry)) ); - if (false === @ldap_control_paged_result_response($ds, $results, $cookie)) { + if ($legacyControlHandling && false === @ldap_control_paged_result_response($ds, $results, $cookie)) { // If the page size is greater than or equal to the sizeLimit value, the server should ignore the // control as the request can be satisfied in a single page: https://www.ietf.org/rfc/rfc2696.txt // This applies no matter whether paged search requests are permitted or not. You're done once you @@ -993,7 +1000,7 @@ class LdapConnection implements Selectable, Inspectable ldap_free_result($results); } while ($cookie && (! $serverSorting || $limit === 0 || count($entries) < $limit)); - if ($cookie) { + if ($legacyControlHandling && $cookie) { // A sequence of paged search requests is abandoned by the client sending a search request containing a // pagedResultsControl with the size set to zero (0) and the cookie set to the last cookie returned by // the server: https://www.ietf.org/rfc/rfc2696.txt @@ -1219,6 +1226,7 @@ class LdapConnection implements Selectable, Inspectable * @param int $sizelimit Enables you to limit the count of entries fetched * @param int $timelimit Sets the number of seconds how long is spend on the search * @param int $deref + * @param int $pageSize The page size to request (Only supported with PHP v7.3+) * * @return resource|bool A search result identifier or false on error * @@ -1230,7 +1238,8 @@ class LdapConnection implements Selectable, Inspectable $attrsonly = 0, $sizelimit = 0, $timelimit = 0, - $deref = LDAP_DEREF_NEVER + $deref = LDAP_DEREF_NEVER, + $pageSize = null ) { $queryString = (string) $query; $baseDn = $query->getBase() ?: $this->getDn(); @@ -1285,6 +1294,20 @@ class LdapConnection implements Selectable, Inspectable throw new LogicException('LDAP scope %s not supported by ldapSearch', $scope); } + $serverctrls = []; + if ($pageSize !== null) { + $serverctrls[] = [ + 'oid' => LDAP_CONTROL_PAGEDRESULTS, + // Do not request the pagination control as a critical extension, as we want the + // server to return results even if the paged search request cannot be satisfied + 'iscritical' => false, + 'value' => [ + 'size' => $pageSize, + 'cookie' => '' + ] + ]; + } + return @$function( $this->getConnection(), $baseDn, @@ -1293,7 +1316,8 @@ class LdapConnection implements Selectable, Inspectable $attrsonly, $sizelimit, $timelimit, - $deref + $deref, + $serverctrls ); }