Active Directory, stangely, also imposes the 1000 limit on the number of
entries returned in a multivalued attribute. So, if you have a group
with 2000 members you will only get the first 1000 users back on the
initial call. Below is some code that works around this odd AD
'feature'. It is ugly....but it works. This code also works on port 389.
use Net::LDAP;
use Net::LDAP::Util;
# Connect to AD make sure to specify version 3
$ldap = new Net::LDAP("myGC.yy.xx.com",port => 3268,debug => 0,version
=>3
) or die "New failed:$@";
# Do an anonymous bind. You MAY have to do an authenticated bind in
your configuration
$result=$ldap->ldapbind() || die "Bind Failed:$@";
# Some error trapping
$err=$result->code;
if ($err){
$errname=Net::LDAP::Util::ldap_error_name($err);
$errtxt=Net::LDAP::Util::ldap_error_text($err);
if ($errtxt){
print "($err) $errtxt\n";
}
else
{
if ($errname){
print "($err) $errname\n";
}
else
{
print "ERR: $err\n";
}
}
exit;
}
# The combination of the search base and filter determine which
object that you
# retrieve
# set search filter to groups of objects. This is what you want to
enumerate NT groups.
$filter="(objectClass=group)";
# Set the search base to the DN of the object that you want to
retrieve. BTW, using this method on
# groups with less than 1000 members works as well.
$base='CN=mygroup,DCyyy,DC=xxx,DC=com';
# Set the initial attribute indexes and name
$found=1;
$startr=0;
$endr=-1;
$startattr="member";
while($found){
# Create the attribute range specification
$startr=$endr+1;
$endr=$startr+999;
$attr="$startattr;range=$startr-$endr";
$saveattr=$attr;
@attr=("$attr");
# Perform the search
$result=$mesg = $ldap->search(base => "$base",filter => $filter,
attrs => [EMAIL PROTECTED],
scope => "sub") or die "search died";
# Some error trapping
$err=$result->code;
if ($err){
if (!($err == 1)){
$errname=Net::LDAP::Util::ldap_error_name($err);
$errtxt=Net::LDAP::Util::ldap_error_text($err);
if ($errtxt){
print "($err) $errtxt\n";
}
else
{
if ($errname){
print "($err) $errname\n";
}
else
{
print "ERR: $err\n";
}
}
}
else
{
print "COUNT=$cnt\n";
}
exit;
}
$found=0;
# OK, get the attribute range...so we can update the value of the
attribute
# on the next pass
foreach $entry ($mesg->all_entries) {
@attr=$entry->attributes;
foreach(@attr){
$curattr=$_;
}
}
# Print out the current chunk of members
foreach $entry ($mesg->all_entries) {
$ar=$entry->get("$curattr");
foreach(@$ar){
$cnt++;
print "$_\n";
}
$found=1;
if ([EMAIL PROTECTED]){
$found=0;
}
}
# Check to see if we got the last chunk. If we did print toe total
and set
# the found flag so we don't search for anymore members
if ($curattr=~/\;range=/){
if ($curattr=~/\-\*/){
print "LASTCOUNT:$cnt\n";
$found=0;
}
}
}
-----Original Message-----
From: Chris Ridd [ <mailto:[EMAIL PROTECTED]> mailto:[EMAIL PROTECTED]
Sent: Tuesday, December 02, 2003 8:50 AM
To: Fox Flanders; [EMAIL PROTECTED]
Subject: Re: Maximum value count for multivalued attributes
On 1/12/03 11:53 pm, Fox Flanders <[EMAIL PROTECTED]> wrote:
> I'm trying to retrieve the list of members in an AD group using
perl-ldap.
> It works fine with a small number of people in a group. But when
doing a
> get_value() on an attribute with say 1000 values, like a large Active
> Directory group with attribute "member", I get 'undef' from
get_value().
> Does anyone know what the value count limit is, and is there a way to
extend
> it?
>
> my (@member) = $entry->get_value("member");
There aren't any limits in Net::LDAP here; it just decodes the entire
attribute and all the values from the BER and puts the result in an
array.
Presumably the length of the encoded SEQUENCE is being encoded and
decoded
correctly.
Are the values actually getting sent to the client? (eg use the debugger
to
print the entry, or use $ldap->debug(3) to dump the sent and received
messages in hex)
Cheers,
Chris