#!/bin/bash /usr/scripts/python.sh # -*- coding: utf-8 -*- # # Auteur : Pierre-Elliott Bécue # Licence : GPLv3 # Date : 01/09/2014 import sys import argparse import re import time from ldap import SIZELIMIT_EXCEEDED from gestion.config import encoding from gestion import affichage from gestion import annuaires_pg import lc_ldap.shortcuts import lc_ldap.objets import lc_ldap.filter2 as lfilter import lc_ldap.crans_utils ENCODING = encoding.in_encoding MACRO_FILTRE_PRISE = re.compile(r'\(prise=(?P[a-zA-Z][0-9]{3})\)') MACRO_FILTRE_ADHESION = re.compile(r'\(adhesion=ok\)') MACRO_FILTRE_CONNEXION = re.compile(r'\(connexion=ok\)') def print_data(data, args): """Récupère les données et les affiche""" dataLen = sum([len(elem) for elem in data.itervalues()]) if dataLen: for (key, elem) in data.iteritems(): if len(elem) == 0: continue _header = affichage.style(u"Résultats de type %s trouvés dans la base." % (key,), ['cyan']) print _header.encode(ENCODING) if len(elem) == 1: elem[0].display( historique=args.historique, blacklist=args.blacklist, disp_adresse=args.adresse, disp_telephone=args.telephone, sshfp=args.sshfp, ipsec=args.ipsec, ) else: print lc_ldap.printing.sprint_list(elem).encode(ENCODING) print "%s résultats" % len(elem) def explore_db(args, ldap): """Utilise le contenu de args pour décider comment explorer la base de données.""" data = search_ldap(args, ldap) data = macro_expand(data, args) return data def search_ldap(args, ldap): """Cherche et trie""" data = {} if args.ldap: search_filter = args.filtre.decode(ENCODING) else: search_filter = lfilter.human_to_ldap(args.filtre.decode(ENCODING)) if args.macro_filtre: search_filter = filter_macro(search_filter) elif args.wild: search_filter = wild_search_filter(search_filter) try: resultats = ldap.search(search_filter, sizelimit=args.limite) except SIZELIMIT_EXCEEDED: raise EnvironmentError("La limite de résultats LDAP (%s) a été dépassée. Vous pouvez l'augmenter avec l'option -l" % (args.limite,)) for elem in resultats: if elem not in data.get(elem.__class__.__name__, []): data.setdefault(elem.__class__.__name__, []).append(elem) return data def macro_expand(data, args): """Gère les macros spécifiques à whos_lc. Permet de récupérer les propriétaires d'objets cherchés, ou les factures ou les machines. De chercher par prise, etc etc""" new_data = dict(data) if args.proprietaire: for elem_list in data.itervalues(): for elem in elem_list: if hasattr(elem, 'proprio'): _proprio = elem.proprio() # On a pas besoin du Crans dans le dico if isinstance(_proprio, lc_ldap.objets.AssociationCrans): continue if _proprio not in data.get(_proprio.__class__.__name__, []): new_data.setdefault(_proprio.__class__.__name__, []).append(_proprio) args.adherent = True return new_data def filter_macro(filtre): """Étend les macros du filtre passé en argument""" thetime = lc_ldap.crans_utils.to_generalized_time_format(time.time()) prise_match = MACRO_FILTRE_PRISE.match(filtre) adhesion_match = MACRO_FILTRE_ADHESION.match(filtre) connexion_match = MACRO_FILTRE_CONNEXION.match(filtre) if prise_match: prise = prise_match.groupdict()['prise'] bat = prise[0] chbre = bat + annuaires_pg.reverse(bat, prise[1:])[0] filtre = filtre.replace(u"(prise=%s)" % (prise,), u"(chbre=%s)" % (chbre,)) if adhesion_match: args.limite = 0 filtre = filtre.replace(u"(adhesion=ok)", u"(&(finAdhesion>=%s)(|(aid=*)(cid=*)))" % (thetime,)) if connexion_match: args.limite = 0 filtre = filtre.replace(u"(connexion=ok)", u"(&(finConnexion>=%s)(|(aid=*)(cid=*)))" % (thetime,)) return filtre def wild_search_filter(filtre): """Recherche sur un gros volume d'attributs dans la base de données""" kw = filtre[1:-1] attr_list = [ u'nom', u'prenom', u'tel', u'mail', u'chbre', u'mailAlias', u'canonicalAlias', u'mailExt', u'uid', u'macAddress', u'host', u'hostAlias', u'ipHostNumber', u'ip6HostNumber', ] filtre = u"(|" for elem in attr_list: filtre += u"(%s=%s*)" % (elem, kw) filtre += u")" return filtre def limits(data, args): """Applique les limitations dans la recherche. Les cas sont a priori conflictuels. """ data_restricted = {} data_restricted.update(data) contentFilter = [] if args.adherent: contentFilter = ["adherent"] elif args.club: contentFilter = ["club"] elif args.machine: contentFilter = ["machineFixe", "machineWifi", "machineCrans", "switchCrans", "borneWifi"] elif args.crans: contentFilter = ["machineCrans", "switchCrans", "borneWifi"] elif args.switch: contentFilter = ["switchCrans"] elif args.borne: contentFilter = ["borneWifi"] # Special cases. elif args.adm: contentFilter = [] out = [] for machine in data.get('machineCrans', []): if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('adm'): out.append(machine) data_restricted = {'machineCrans' : out,} elif args.special: contentFilter = [] out = [] for machine in data.get('machineCrans', []): if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('special'): out.append(machine) data_restricted = {'machineCrans' : out,} elif args.serveur: contentFilter = [] out = [] for machine in data.get('machineCrans', []): if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('serveur'): out.append(machine) data_restricted = {'machineCrans' : out,} if contentFilter: data_restricted = {a: data.get(a, []) for a in contentFilter} return data_restricted if __name__ == "__main__": parser = argparse.ArgumentParser(description="Recherche dans la base des adhérents", add_help=False) parser.add_argument('-A', '--adresse', help="Affiche l'adresse de l'adhérent.", action="store_true") parser.add_argument('-d', '--blacklist', type=int, help="Choix du nombre d'entrées blacklist à afficher pour les entrées détaillées.", action="store", default=10) parser.add_argument('-h', '--help', help="Affiche ce message et quitte.", action="store_true") parser.add_argument('-i', '--ipsec', help="Affichage de la clef wifi de la machine.", action="store_true") parser.add_argument('-l', '--limite', type=int, help="Modifier la taille limite de recherche dans la base LDAP", action="store", default=1000) parser.add_argument('-L', '--historique', type=int, help="Choix du nombre d'entrées d'historique à afficher pour les entrées détaillées.", action="store", default=10) parser.add_argument('-s', '--sshfp', help="Affiche les fingerprint SSH si elles existent.", action="store_true") parser.add_argument('-t', '--ldap', help="Utiliser les filtres tels que définis dans ldap", action="store_true") parser.add_argument('-T', '--telephone', help="Afficher le numéro de téléphone de l'adhérent.", action="store_true") parser.add_argument('--test', help="Se connecter à la base de test", action="store_true") parser.add_argument('-v', '--verbose', help="Rend le script (très) verbeux.", action="store_true") parser.add_argument('filtre', type=str, nargs="?", help="Le filtre whos à utiliser") macro_group = parser.add_mutually_exclusive_group(required=False) macro_group.add_argument('-f', '--macro-filtre', help="Flag activant la gestion des macros pour le filtre LDAP.", action="store_true") macro_group.add_argument('-w', '--wild', help="Cherche de façon agressive dans la base de données à partir du filtre", action="store_true") type_group = parser.add_mutually_exclusive_group(required=False) type_group.add_argument('-a', '--adherent', help="Limite l'affichage aux adhérents.", action="store_true") type_group.add_argument('--adm', help="Limite l'affichage aux machines adm.", action="store_true") type_group.add_argument('-b', '--borne', help="Limite l'affichage aux bornes.", action="store_true") type_group.add_argument('-c', '--club', help="Limite l'affichage aux clubs.", action="store_true") type_group.add_argument('--crans', help="Limite l'affichage aux machines crans.", action="store_true") type_group.add_argument('-m', '--machine', help="Limite l'affichage aux machines.", action="store_true") type_group.add_argument('-P', '--proprietaire', help="Récupère le propriétaire de l'objet cherché.", action="store_true") type_group.add_argument('--serveur', help="Limite l'affichage aux serveurs.", action="store_true") type_group.add_argument('--special', help="Limite l'affichage aux machines spéciales.", action="store_true") type_group.add_argument('--switch', help="Limite l'affichage aux switches (pas encore implémenté).", action="store_true") args = parser.parse_args() if args.help: parser.print_help() sys.exit(0) if args.test: LDAP = lc_ldap.shortcuts.lc_ldap_test() else: LDAP = lc_ldap.shortcuts.lc_ldap_readonly() DATA = explore_db(args, LDAP) DATA = limits(DATA, args) print_data(DATA, args)