| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- #!/usr/bin/env perl
- use strict;
- use warnings;
- use Config::Tiny ();
- use File::Slurper ();
- use Net::LDAP ();
- use JSON::XS ();
- die "No config file!" if !-f 'ldapscanner.cfg';
- my $cfg = Config::Tiny->read('ldapscanner.cfg');
- my @servers = split( ',', $cfg->{'server'}{'hosts'} );
- my $proto = 'ldap';
- my %extra_args = (
- 'onerror' => ( $cfg->{'prefs'}{'loglevel'} eq 'warn' ) ? 'warn' : 'die',
- 'debug' => $cfg->{'prefs'}{'loglevel'} eq 'debug',
- 'port' => $cfg->{'server'}{'port'},
- 'timeout' => $cfg->{'server'}{'timeout'},
- );
- if( $cfg->{'server'}{'ldaps'} ) {
- $proto = 'ldaps';
- $extra_args{'verify'} = 'no';
- }
- $extra_args{'scheme'} = $proto;
- _log( "info", "Connecting..." );
- my $conn = Net::LDAP->new( \@servers, %extra_args ) or die $@;
- my @bind_args;
- my $user = 'anonymous';
- if( $cfg->{'creds'}{'dn'} && $cfg->{'creds'}{'pass'} ) {
- push @bind_args, $cfg->{'creds'}{'dn'}, 'password', $cfg->{'creds'}{'pass'};
- $user = "DN: $cfg->{'creds'}{'dn'}";
- }
- _log( "info", "Binding as $user..." );
- my $result = $conn->bind(@bind_args);
- $result->code and die $result->error;
- _log( "info", "Beginning search..." );
- $result = $conn->search(
- base => $cfg->{'search'}{'base'},
- filter => $cfg->{'search'}{'filter'},
- );
- $result->code and die $result->error;
- my $old_entries = {};
- if( -f '.last.json' ) {
- _log( "info", "Stored run data found, will compare against previous run." );
- my $raw = File::Slurper::read_text('.last.json');
- $old_entries = JSON::XS->new->decode($raw);
- } else {
- _log( "info", "No run data found. Storing current data and exiting." );
- }
- my $new_entries = {};
- foreach my $entry ($result->entries) {
- my $hr = {};
- foreach my $attr ($entry->attributes( 'nooptions' => 1 )) {
- $hr->{$attr} = $entry->get_value( $attr, 'nooptions' => 1 );
- }
- $new_entries->{$entry->dn} = $hr;
- }
- _log( "info", "Found " . scalar(keys(%$new_entries)) . " records total" );
- my $diff = {
- 'added' => { map { $_ => $new_entries->{$_} } grep { !exists($old_entries->{$_}) } keys(%$new_entries) },
- 'removed' => { map { $_ => $old_entries->{$_} } grep { !exists($new_entries->{$_}) } keys(%$old_entries) },
- };
- File::Slurper::write_text( '.current_diff.json', JSON::XS->new->pretty->encode($diff) );
- File::Slurper::write_text( '.last.json', JSON::XS->new->pretty->encode($new_entries) );
- my @skip = split( ',', $cfg->{'display'}{'ignore_attrs'} );
- _log( "warn", "Added records : " . scalar(keys(%{$diff->{'added'}})) );
- _print_records( $diff->{'added'}, @skip );
- _log( "warn", "Removed records: " . scalar(keys(%{$diff->{'removed'}})) );
- _print_records( $diff->{'removed'}, @skip );
- sub _print_records {
- my ( $hr, @skip ) = @_;
- foreach my $key ( keys(%$hr) ) {
- _log( "warn", "------------------------------------------------" );
- _log( "warn", "DN: " . $key );
- foreach my $attr ( keys(%{$hr->{$key}}) ) {
- next if grep { $_ eq $attr } @skip;
- _log( "warn", " $attr: $hr->{$key}{$attr}" );
- }
- }
- return;
- }
- sub _log {
- my ( $level, $msg ) = @_;
- my %levels = (
- 'warn' => 1,
- 'error' => 2,
- 'info' => 3,
- 'debug' => 4,
- );
- my $loglevel = $levels{$cfg->{'prefs'}{'loglevel'}};
- die "Bad log level" if !$loglevel;
- print "$msg\n" if $levels{$level} <= $loglevel;
- return;
- }
- 0;
|