Since I did not find any clean solutions, I decided to go with the first approach: Filtering By Object-Sids.
There are limitations in this workaround:
- It works only for objects with objects, that is, users and groups.
- It is assumed that all users / groups are created by the same authority.
- He suggests that there is not enough missing relative security identifiers than the size limit.
The idea is to first read all possible objects and select the one with the lowest relative SID. Relative SID - last fragment in SID:
S-1-5-21-3188256696-111411151-3922474875-1158
Suppose this is the lowest relative SID in the search, which returns only "Partial search results". Suppose further that the size limit is 1000.
Then the program performs the following actions: It searches for all objects with SIDs between
S-1-5-21-3188256696-111411151-3922474875-1158
and
S-1-5-21-3188256696-111411151-3922474875-0159
then everything in between
S-1-5-21-3188256696-111411151-3922474875-1158
and
S-1-5-21-3188256696-111411151-3922474875-2157
and so on, until one of the queries returns null objects.
There are several problems with this approach, but it is enough for my purposes.
Code:
$filter = '(objectClass=Group)'; $attributes = array('objectsid','cn'); //objectsid needs to be set $result = array(); $maxPageSize = 1000; $searchStep = $maxPageSize-1; $adResult = @$adConn->search($filter,$attributes); //Supress warning for first query (because it exceeds the size limit) //Read smallest RID from the resultset $minGroupRID = ''; for($i=0;$i<$adResult['count'];$i++){ $groupRID = unpack('V',substr($adResult[$i]['objectsid'][0],24)); if($minGroupRID == '' || $minGroupRID>$groupRID[1]){ $minGroupRID = $groupRID[1]; } } $sidPrefix = substr($adResult[$i-1]['objectsid'][0],0,24); //Read last objectsid and cut off the prefix $nextStepGroupRID = $minGroupRID; do{ //Search for all objects with a lower objectsid than minGroupRID $adResult = $adConn->search('(&'.$filter.'(objectsid<='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID))).')(objectsid>='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID-$searchStep))).'))', $attributes); for($i=0;$i<$adResult['count'];$i++){ $RID = unpack('V',substr($adResult[$i]['objectsid'][0],24)); //Extract the relative SID from the SID $RIDs[] = $RID[1]; $resultSet = array(); foreach($attributes as $attribute){ $resultSet[$attribute] = $adResult[$i][$attribute][0]; } $result[$RID[1]] = $resultSet; } $nextStepGroupRID = $nextStepGroupRID-$searchStep; }while($adResult['count']>1); $nextStepGroupRID = $minGroupRID; do{ //Search for all object with a higher objectsid than minGroupRID $adResult = $adConn->search('(&'.$filter.'(objectsid>='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID))).')(objectsid<='.preg_replace('/../','\\\\$0',bin2hex($sidPrefix.pack('V',$nextStepGroupRID+$searchStep))).'))', $attributes); for($i=0;$i<$adResult['count'];$i++){ $RID = unpack('V',substr($adResult[$i]['objectsid'][0],24)); //Extract the relative SID from the SID $RIDs[] = $RID[1]; $resultSet = array(); foreach($attributes as $attribute){ $resultSet[$attribute] = $adResult[$i][$attribute][0]; } $result[$RID[1]] = $resultSet; } $nextStepGroupRID = $nextStepGroupRID+$searchStep; }while($adResult['count']>1); var_dump($result);
The $ adConn-> method looks like this:
function search($filter, $attributes = false, $base_dn = null) { if(!isset($base_dn)){ $base_dn = $this->baseDN; } $entries = false; if (is_string($filter) && $this->bind) { if (is_array($attributes)) { $search = ldap_search($this->resource, $base_dn, $filter, $attributes); } else { $search = ldap_search($this->resource, $base_dn, $filter); } if ($search !== false) { $entries = ldap_get_entries($this->resource, $search); } } return $entries; }