#! /usr/bin/perl -w
#---------------------------------------------------------------------------
# Check LDAP query server plugin Pandora FMS
#
# Request an LDAP server and count entries returned
# Artica ST 
# Copyright (C) 2013 mario.pulido@artica.es
#
# License: GPLv2+
#---------------------------------------------------------------------------
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# GPL License: http://www.gnu.org/licenses/gpl.txt
#---------------------------------------------------------------------------

my $VERSION          = 'v1r1';
#---------------------------------------------------------------------------
# Modules
#---------------------------------------------------------------------------
use strict;
use Getopt::Long;
&Getopt::Long::config('bundling');
use File::Basename;
use Net::LDAP;

#---------------------------------------------------------------------------
# Options
#---------------------------------------------------------------------------
my $progname = basename($0);
my $help;
my $version;
my $verbose = 0;
my $host;
my $authentication;
my $log_file;
my $name;
my $port;
my $regexp;
my $eregexp;
my $exclude;
my $minute = 60;
my $url;


# For LDAP plugins
my $ldap_binddn;
my $ldap_bindpw;
my $ldap_filter;
my $ldap_base;
my $ldap_scope;

GetOptions(
    'h'          => \$help,
    'help'       => \$help,
    'v+'         => \$verbose,
    'verbose+'   => \$verbose,
    'H:s'        => \$host,
    'host:s'     => \$host,
    'p:i'       => \$port,
    'port:i'    => \$port,
    'u:s'      => \$ldap_binddn,
    'binddn:s' => \$ldap_binddn,
    'P:s'      => \$ldap_bindpw,
    'bindpw:s' => \$ldap_bindpw,
    'Q:s'      => \$ldap_filter,
    'filter:s' => \$ldap_filter,
    'b:s'      => \$ldap_base,
    'base:s'   => \$ldap_base,
    's:s'      => \$ldap_scope,
    'scope:s'  => \$ldap_scope,
);


#---------------------------------------------------------------------------
# Functions
#---------------------------------------------------------------------------

# DEBUG function
sub verbose {
    my $output_code = shift;
    my $text        = shift;
    if ( $verbose >= $output_code ) {
        printf "VERBOSE $output_code ===> %s\n", $text;
    }
}

# check if -H -b and -F is used
sub check_host_param {
    if ( !defined($host)) {
		
    print "-H, --host=STRING\n";
    print "\tIP or name (FQDN) of the directory. You can use URI (ldap://, ldaps://, ldap+tls://)\n";
    print "-p, --port=INTEGER\n";
    print "\tDirectory port to connect to.\n";
    print "-u, --binddn=STRING\n";
    print "\tBind DN. Bind anonymous if not present.\n";
    print "-P, --bindpw=STRING\n";
    print "\tBind passwd. Need the Bind DN option to work.\n";
    print "-Q, --filter=STRING\n";
    print "\tLDAP search filter.\n";
    print "-b, --base=STRING\n";
    print "\tLDAP search base.\n";
    print "-s, --scope=STRING\n";
    print "\tLDAP search scope\n";
    print "\n";
    
    print "Version=$VERSION";
    }
}


# Bind to LDAP server
sub get_ldapconn {
    &verbose( '3', "Enter &get_ldapconn" );
    my ( $server, $binddn, $bindpw ) = @_;
    my ( $useTls, $tlsParam );

    # Manage ldap+tls:// URI
    if ( $server =~ m{^ldap\+tls://([^/]+)/?\??(.*)$} ) {
        $useTls   = 1;
        $server   = $1;
        $tlsParam = $2 || "";
    }
    else {
        $useTls = 0;
    }

    my $ldap = Net::LDAP->new( $server );

    return ('1') unless ($ldap);
    &verbose( '2', "Connected to $server" );

    if ($useTls) {
        my %h = split( /[&=]/, $tlsParam );
        my $message = $ldap->start_tls(%h);
        $message->code
          && &verbose( '1', $message->error )
          && return ( $message->code, $message->error );
        &verbose( '2', "startTLS succeed on $server" );
    }

    if ( $binddn && $bindpw ) {

        # Bind witch credentials
        my $req_bind = $ldap->bind( $binddn, password => $bindpw );
        $req_bind->code
          && &verbose( '1', $req_bind->error )
          && return ( $req_bind->code, $req_bind->error );
        &verbose( '2', "Bind with $binddn" );
    }
    else {
        my $req_bind = $ldap->bind();
        $req_bind->code
          && &verbose( '1', $req_bind->error )
          && return ( $req_bind->code, $req_bind->error );
        &verbose( '2', "Bind anonym" );
    }
    &verbose( '3', "Leave &get_ldapconn" );
    return ( '0', $ldap );
}

# Get the master URI from cn=monitor
sub get_entries {
    &verbose( '3', "Enter &get_entries" );
    my ( $ldapconn, $base, $scope, $filter ) = @_;
    my $message;
    my $count;
    $message = $ldapconn->search(
        base   => $base,
        scope  => $scope,
        filter => $filter,
        attrs  => ['1.1']
    );
    $message->code
      && &verbose( '1', $message->error )
      && return ( $message->code, $message->error );
    $count = $message->count();
    &verbose( '2', "Found $count entries" );
    &verbose( '3', "Leave &get_entries" );
    return ( 0, $count );
}

#---------------------------------------------------------------------------
# Main
#---------------------------------------------------------------------------

# Options checks
&check_host_param();
#&check_base_param();

# Default values
#$ldap_filter ||= "(objectClass=*)";
$ldap_scope  ||= "sub";

my $errorcode;

# Connect to the directory
# If $host is an URI, use it directly
my $ldap_uri;
if ( $host =~ m#ldap(\+tls)?(s)?://.*# ) {
    $ldap_uri = $host;
    $ldap_uri .= ":$port" if ( $port and $host !~ m#:(\d)+# );
}
else {
    $ldap_uri = "ldap://$host";
    $ldap_uri .= ":$port" if $port;
}

my $ldap_server;
( $errorcode, $ldap_server ) =
  &get_ldapconn( $ldap_uri, $ldap_binddn, $ldap_bindpw );
if ($errorcode) {
    print "Can't connect to $ldap_uri.\n";
}

# Request LDAP
my $nb_entries;
( $errorcode, $nb_entries ) =
  &get_entries( $ldap_server, $ldap_base, $ldap_scope, $ldap_filter );
if ($errorcode) {
    print "0\n";
}

#---------------------------------------------------------------------------
# Exit 
#---------------------------------------------------------------------------

# Print $nb_entries and exit
print "$nb_entries\n";
exit;