#!/usr/bin/env python3
'''special agent call file

Set the environment variable ``LDAP_VERIFY_TLS=1`` or pass ``--verify-tls``
to enforce TLS certificate verification.
'''
# -*- mode: Python; encoding: utf-8; indent-offset: 4; autowrap: nil -*-

# (c) Michael Honkoop <mhonkoop@comsolve.nl>

# License: GNU General Public License v2

import os
import argparse
import sys
import ldap
from cmk_addons.plugins.edirectory_monitor.lib import (
    print_sections,
)

# possible subsections of cn=Monitor
monitor_sections = [
    "Agent",
    "Dclient",
    "DHOST",
    "LDAP",
    "RecordManager",
    "IDM",
]

def main():
    def parse_exclude_list(value):
    # Split by comma, strip whitespace, remove empty items
        return [item.strip() for item in value.split(',') if item.strip()]

    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--server', required=True, help='Server URI (required)')
    parser.add_argument('-u', '--user', required=True, help='Username (required)')
    parser.add_argument('-p', '--password', required=True, help='Password (required)')
    parser.add_argument('--exclude', type=parse_exclude_list, help='Excluded section(s) comma separated (optional)')
    parser.add_argument('--verify-tls', '--verify-tls', help='Enforce certificate validation (optional)')

    args = parser.parse_args()
    print(args)
    exclude_sections = []
    if args.exclude is not None:
        # Split the value by commas
        exclude_sections = args.exclude
    else:
        exclude_sections = None

    if args.verify_tls is not None:
        verify_tls = True
    else:
        verify_tls = False
            
    env_verify = os.environ.get("LDAP_VERIFY_TLS", "").lower()
    if env_verify in ("1", "true", "yes"):
        verify_tls = True
       
    ldap_uri = args.server
    binddn = args.user 
    pw = args.password
    basedn = "cn=Monitor"
    searchFilter = "(objectClass=*)"
    searchAttribute = ["*"]
    searchScope = ldap.SCOPE_SUBTREE

    l = None
    try:
        if verify_tls:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND)
        else:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
        # set timeout to 40 seconds for network
        ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 40)
        # Create LDAPObject instance with given uri
        l = ldap.initialize(ldap_uri)
        # Set LDAP protocol version used
        l.protocol_version = ldap.VERSION3

        try:
            # Attempt to bind with given credentials
            l.simple_bind_s(binddn, pw)
            
            if exclude_sections is None:
                ldap_result_id = l.search(basedn, searchScope, searchFilter, searchAttribute)

                result_set = []

                while True:
                    result_type, result_data = l.result(ldap_result_id, 0, timeout=40)
                    if (result_data == []):
                        break
                    elif result_type == ldap.RES_SEARCH_ENTRY:
                        result_set.append(result_data)
            else:
                result_set = []

                for entry in monitor_sections:
                    if entry.lower() in exclude_sections:
                        continue
                    else:
                        ldap_result_id = l.search("cn=" + entry + "," + basedn, searchScope, searchFilter, searchAttribute)

                        while True:
                            result_type, result_data = l.result(ldap_result_id, 0, timeout=40)
                            if (result_data == []):
                                break
                            elif result_type == ldap.RES_SEARCH_ENTRY:
                                result_set.append(result_data)
                                
            print('<<<edirectory_monitor_agent:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=Agent" in element:
                            print_sections(result_set[i])
            print('<<<edirectory_monitor_dclient:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=Dclient" in element:
                            print_sections(result_set[i])
            print('<<<edirectory_monitor_dhost:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=DHOST" in element:
                            print_sections(result_set[i])
            print('<<<edirectory_monitor_ldap:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=LDAP" in element:
                            print_sections(result_set[i])
            print('<<<edirectory_monitor_recordmanager:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=RecordManager" in element:
                            print_sections(result_set[i])
            print('<<<edirectory_monitor_idm:sep(124)>>>')
            for i in range(len(result_set)):
                for val in result_set[i]:
                    for element in val:
                        if "cn=IDM" in element:
                            print_sections(result_set[i])

        except ldap.INVALID_CREDENTIALS as e:
            print(f"Authentication to the LDAP host has failed: {e}")
            return print(f"Authentication to the LDAP host has failed: {e}")
        
        except ldap.LDAPError as e:
            print(f"LDAP error during bind/search: {e}")
            return print(f"LDAP error during bind/search: {e}")
        
    except ldap.LDAPError as e:
        print(f"Failed to initialize LDAP connection: {e}")
        return print(f"Failed to initialize LDAP connection: {e}")
    finally:
        if l is not None:
            try:
                l.unbind_s()
            except ldap.LDAPError:
                pass

if __name__ == "__main__":
    main()

