#!/pkg/perl/5.8/5.6.1/bin/perl # tel - AD Contact Lookup tool # adam.prato @ gmail.com use Net::LDAP; use Getopt::Std; use Data::Dumper; use strict; my ($binddn, $bindpass, $ldap, $mesg, $search, $acct, $filter, $base); my ($output, $outfh, $stdout, $me, $ldapbound, $limit, $dnfile, $dcc); my $delim = "|"; my @defatts = ('givenName','sn','cn','title','description','department','streetAddress','physicalDeliveryOfficeName','l','st','postalCode','c','telephoneNumber','mobile','pager','mail','sAMAccountName','mailnickname'); my $defattr = 'sAMAccountName'; my %o; if (defined($ENV{'TELDN'})) { $dnfile = $ENV{'TELDN'}; } else { $dnfile = $ENV{'HOME'} . "/.addn"; } ### Replace the following with your site specific information # The binddn can be stored in a file ~/.addn (make sure the permisisons on this # file is protected) in the format - DN:PASSWORD $binddn = "CN=USER,OU=Users,OU=New York,OU=_USA,DC=DOMAIN,DC=DOM"; # This is the base to search for ldap entries $base = "dc=DOMAIN,dc=COM"; # This should be the domain controller $dcc = "DCHOSTNAME"; sub Usage { ($me = $0 ) =~ s,^.*/,,; print "Usage: $me [options] pattern | -s pattern | -f filter | -u accountname\n" . "\t-s pattern search $defattr for 'pattern'\n" . "\t-f filter search for filter\n" . "\t-u username match $defattr for 'username'\n" . "\t-r number reverse lookup\n" . "Options:\n" . "\t-a attributes comma separated list of attributes to dump\n" . "\t-A attribute set the default attribute for searching\n". "\t-b base base dn for ldap search\n" . "\t-B binddn base dn for ldap search\n" . "\t-c output in csv\n" . "\t-C set default attribute to 'cn'\n" . "\t-d delimiter delimiter for csv output\n" . "\t-D dnfile path to file with dn information\n" . "\t-l limit ldap sizelimit\n" . "\t-o filename output to file\n" . "\t-P password password for bind to AD\n" . "\t-v dump all attributes of matching search\n" . "" ; exit(0); } $stdout = *STDOUT; $output = $stdout; if (@ARGV < 1) { Usage; } elsif ((@ARGV == 1) && ($ARGV[0] ne "-h")) { $filter = "($defattr=*" . $ARGV[0] . "*)"; } else { getopts("cCvxA:a:B:b:d:D:f:h:l:o:P:r:s:u:v:x:",\%o); if (!(defined($o{s}) | defined($o{u}) | defined($o{f}) | defined($o{r}))) { Usage; } if (defined($o{h})) { Usage; } if (defined($o{s})) { $acct = "*$o{s}*"; } if (defined($o{u})) { $acct = $o{u}; } if (defined($o{C})) { $defattr = "cn"; } if (defined($o{f})) { $filter = $o{f}; } else { $filter = "($defattr=$acct)"; } if (defined($o{r})) { $filter = "(|(telephoneNumber=*$o{r}*)(mobile=*$o{r}*)(pager=*$o{r}*))"; } if (defined($o{B})) { if (!defined $o{P}) { die "Must provide -p password with -B binddn\n"; } $binddn = $o{B}; $bindpass = $o{P}; $dnfile = ""; } if (defined($o{D})) { $dnfile = $o{D}; } if (defined($o{P})) { $bindpass = $o{P}; } else { $bindpass = ''; } if ($bindpass != "") { print STDERR "Use -p to set an AD password (bindpass), or set one in the script\n"; exit(1); } if (defined($o{x})) { push @defatts, ('extensionAttribute1','extensionAttribute3'); } if (defined($o{o})) { if (!open(OUTFH, "> $o{o}")) { print STDERR"Couldn't open file ($o{o}) for writing: $!\n"; exit(1); } else { print STDERR"Will write results to $o{o}\n"; $output = *OUTFH; } } if (defined($o{a})) { @defatts = split(/\,/,$o{a}); } if (defined($o{d})) { $delim = $o{d}; } if (defined($o{b})) { $base = $o{b}; } if (defined($o{l})) { $limit = $o{l}; } } sub cleanup { print STDERR "\nCleaning up...\n"; if ($ldapbound > 0) { $mesg = $ldap->unbind; print STDERR "Unbinding the LDAP connection...\n"; die $mesg->error; } } # if ( -f $dnfile) { if (open(TELPASS, $dnfile)) { my $line = ; close(TELPASS); if ($line =~ /(^[^:]*):(.*)/) { if ($1 !~ /^$/) { $binddn = $1; } if ($2 !~ /^$/) { $bindpass = $2; } if ($binddn !~ /DC\=/i) { $binddn = "CN=" . $binddn . ",OU=Users,OU=New York,OU=_USA,DC=DOMAIN,DC=COM"; } } } } # /* main() */ $SIG{'INT'} = \&cleanup; $SIG{'QUIT'} = \&cleanup; $|++; $ldap = Net::LDAP->new($dcc, version => 3) or die "Could not connect to the AD: $!\n" . "\n\tusing DN: $binddn\n"; $mesg = $ldap->bind($binddn, password => $bindpass); #$mesg = $ldap->bind; if ($mesg->code) { die "Could not bind to the AD : " . $mesg->error . "\n\tUsing DN [$binddn]\n"; } else { print STDERR "[Bound ldap using dn: $binddn]\n\n"; $ldapbound++ } $search = $ldap->search ( base => $base, filter => $filter, sizelimit => 0, timelimit => 0 ); $search->code && die $search->error; if ($search->count < 1) { print STDERR "AD lookup (filter = $filter, base = $base) failed (" . $search->count . ")\n"; } else { print STDERR "Results (" . $search->count . ") for filter : $filter, base = $base :\n"; } my $h = $search->as_struct; my @e = $search->entries; #foreach my $ent (sort keys(%{$h})) { # my $line; # my @atts; # # if (defined($o{d})) { # @atts = sort keys(%{$h->{$ent}}); # } else { # @atts = @defatts; # } # # if (!defined($o{c})) { # print "-" x 60 . "\n"; # print "[$ent]\n"; # } # # foreach my $att (@atts) { # if (defined($o{c})) { # $line .= $att . $delim ; # } else { # $att =~ tr/A-Z/a-z/; # $line .= sprintf ("%31s:", $att); # foreach my $attderef (@{$h->{$ent}{$att}}) { # $line .= " $attderef" # } # } # $line .= "\n"; # } # print $output $line ; #} #$mesg = $ldap->unbind ; #exit; if (defined($o{c}) && !defined($o{v})) { print $output join($delim, @defatts) . "\n"; } foreach my $entry ($search->entries) { my $line; my @atts; my @csv; if (defined($o{v})) { @atts = sort $entry->attributes; } else { @atts = @defatts; } if (!defined($o{c})) { print $output "-=" x 39 . "\n"; print $output "[" . $entry->dn . "]\n"; } foreach my $att (@atts) { if (defined($o{c})) { push @csv, $entry->get_value($att); } else { $line .= sprintf ("%31s: %s\n" , $att, $entry->get_value($att)); } } if (defined($o{c})) { $line = join($delim, @csv); } print $output $line . "\n"; } $mesg = $ldap->unbind ; print STDERR "\n"; # /* end main() */