#!/usr/bin/perl
#printMembers.pl
#given the name of a group (assume object class is groupOfUniqueNames) will
#display the members of the group including members of any groups that may be a member
#of the original group
#*Now Handles Netscape Dynamic Groups*
#
#By default it will display the DN of the member entries, you can specify a particular
#attribute you wish to display instead (e.g. mail attribute)
#example: printMembers.pl -n "Accounting Managers"
#optionally you can also specify the host, port, binded search and search base.
#Mark Wilcox mark@mjwilcox.com
#
#first version: August 8, 1999
#second version: August 15, 1999
use strict;
use Carp;
use Net::LDAP;
use URI;
use vars qw($opt_h $opt_p $opt_D $opt_w $opt_b $opt_n $opt_a );
use Getopt::Std;
my $usage = "usage: $0 [-hpDwba] -n group_name";
die $usage unless @ARGV;
getopts('h:p:D:w:b:n:a:');
die $usage unless ($opt_n);
my $DEBUG = 0; #DEBUG 1 if you want debugging info
#get configuration setup
$opt_h = "airwolf" unless $opt_h;
$opt_p = 389 unless $opt_p;
$opt_b = "o=airius.com" unless $opt_b;
my $isGroup = 0; #checks for group or not
my $ldap = new Net::LDAP ($opt_h, port=> $opt_p);
#will bind as specific user if specified else will be binded anonymously
$ldap->bind($opt_D, password=> $opt_p) || die "failed to bind as $opt_D";
#get the group DN
my @attrs = ['dn'];
eval
{
my $mesg = $ldap->search(
base => $opt_b,
filter => "(&(cn=$opt_n)(objectclass=groupOfUniqueNames))",
attrs => @attrs
);
die $mesg->error if $mesg->code;
my $entry = $mesg->pop_entry();
my $groupDN = $entry->dn();
&printMembers($groupDN,$opt_a);
$isGroup = 1;
};
print "$opt_n is not a group" unless ($isGroup);
$ldap->unbind();
sub printMembers
{
my ($dn,$attr) = @_;
my @attrs = ["uniquemember","memberurl"];
my $mesg = $ldap->search(
base => $dn,
scope => 'base',
filter => "objectclass=*",
attrs => @attrs
);
die $mesg->error if $mesg->code;
#eval protects us if nothing is returned in the search
eval
{
#should only be 1 entry
my $entry = $mesg->pop_entry();
print "\nMembers of group: $dn\n";
#returns an array reference
my $values = $entry->get_value("uniquemember", asref => 1);
foreach my $val (@{$values})
{
my $isGroup = 0; #lets us know if the entry is also a group, default no
#change val variable to attribute
#now get entry of each member
#is a bit more efficient since we use the DN of the member
#as our search base, greatly reducing the number of entries we
#must search through for a match to 1 :)
my @entryAttrs = ["objectclass","memberurl",$attr];
$mesg = $ldap->search(
base => $val,
scope => 'base',
filter => "objectclass=*",
attrs => @entryAttrs
);
die $mesg->error if $mesg->code;
eval
{
my $entry = $mesg->pop_entry();
if ($attr)
{
my $values = $entry->get_value($attr, asref => 1);
foreach my $vals (@{$values})
{
print $vals,"\n";
}
}
else
{
print "$val\n";
}
my $values = $entry->get_value("objectclass", asref => 1);
# This value is also a group, print the members of it as well
&printMembers($entry->dn(),$attr) if (grep /groupOfUniqueNames/i, @{$values});
};
}
my $urls = $entry->get_value("memberurl", asref => 1);
&printDynamicMembers($entry->dn(),$urls,$attr) if ($urls);
};
return 0;
}
#prints out a search results
#for members of dynamic group (as supported by the Netscape Directory Server)
#*Note this may or may not return all of the resulting members and their attribute values
#depending on how the LDAP connection is binded. Normally users who are not binded as the Directory Manager
#are restricted to 2000 or less total search results.
#In theory a dynamic group could have a million or more entries
sub printDynamicMembers
{
my ($entryDN,$urls,$attr) = @_;
print "\nMembers of dynamic group: $entryDN\n";
foreach my $url (@{$urls})
{
print "url is $url\n" if $DEBUG;
my $uri;
eval
{
$uri = URI->new($url);
} ;
print "ref ",ref($uri),"\n" if $DEBUG;
my $base = $uri->dn();
print "base is $base\n" if $DEBUG;
my $scope = $uri->scope();
my $filter = $uri->filter();
my @attrs = [$attr];
my $mesg = $ldap->search(
base => $base,
scope => $scope,
filter => $filter,
attrs => @attrs
);
#print results
my $entry;
while ($entry = $mesg->pop_entry())
{
if ($attr)
{
my $values = $entry->get_value($attr, asref => 1);
foreach my $vals (@{$values})
{
print $vals,"\n";
}
}
else
{
print $entry->dn(),"\n";
}
}
}
return 0;
}
=head1 NAME
printMembers.pl
=head1 DESCRIPTION
Prints out the members of a given group, including members of groups that are also members of the given group.
Defaults to printing out members by DN, but you can specify other attributes for display
=head1 USAGE
perl printMembers.pl -n "Accounting Managers"
Members of group: cn=Accounting Managers,ou=groups,o=airius.com
uid=scarter, ou=People, o=airius.com
uid=tmorris, ou=People, o=airius.com
cn=HR Managers,ou=groups,o=airius.com
Members of group: cn=HR Managers,ou=groups,o=airius.com
uid=kvaughan, ou=People, o=airius.com
uid=cschmith, ou=People, o=airius.com
cn=PD Managers,ou=groups,o=airius.com
Members of group: cn=PD Managers,ou=groups,o=airius.com
uid=kwinters, ou=People, o=airius.com
uid=trigden, ou=People, o=airius.com
Here's an example of the same group but instead print the cn attribute
of each entry:
Members of group: cn=Accounting Managers,ou=groups,o=airius.com
Sam Carter
Ted Morris
HR Managers
Members of group: cn=HR Managers,ou=groups,o=airius.com
Kirsten Vaughan
Chris Schmith
PD Managers
Members of group: cn=PD Managers,ou=groups,o=airius.com
Kelly Winters
Torrey Rigden
And same group but with the mail attribute:
Members of group: cn=Accounting Managers,ou=groups,o=airius.com
scarter@airius.com
tmorris@airius.com
Members of group: cn=HR Managers,ou=groups,o=airius.com
kvaughan@airius.com
cschmith@airius.com
Members of group: cn=PD Managers,ou=groups,o=airius.com
kwinters@airius.com
trigden@airius.com
=cut
|