From caf1bb803e8fbad3d2e73bde5a27bc9fd423a440 Mon Sep 17 00:00:00 2001 From: pauget Date: Sat, 11 Jun 2005 19:02:24 +0200 Subject: [PATCH] Rcriture de generate pour la migration. Mise en place du firewall sur toutes les machines darcs-hash:20050611170224-41617-068d285a581f2c65799ca3fbe33a57a3075b9d03.gz --- gestion/gen_confs/droits.py | 242 ++++--- gestion/gen_confs/firewall.py | 975 ++++++++++++++++++++++++++-- gestion/gen_confs/firewall_bleu.py | 119 ---- gestion/gen_confs/firewall_crans.py | 423 ------------ gestion/gen_confs/firewall_komaz.py | 385 ----------- gestion/gen_confs/generate.py | 738 ++++++++------------- gestion/gen_confs/supervison.py | 333 ++++++++++ gestion/gest_crans.py | 2 +- gestion/ldap_crans.py | 41 +- gestion/mail.py | 53 -- gestion/whos.py | 36 +- 11 files changed, 1681 insertions(+), 1666 deletions(-) delete mode 100755 gestion/gen_confs/firewall_bleu.py delete mode 100755 gestion/gen_confs/firewall_crans.py delete mode 100755 gestion/gen_confs/firewall_komaz.py create mode 100755 gestion/gen_confs/supervison.py delete mode 100755 gestion/mail.py diff --git a/gestion/gen_confs/droits.py b/gestion/gen_confs/droits.py index 659989e1..3e53a75b 100755 --- a/gestion/gen_confs/droits.py +++ b/gestion/gen_confs/droits.py @@ -1,24 +1,31 @@ #! /usr/bin/env python # -*- coding: iso-8859-15 -*- -import sys, signal, os, smtplib +import sys, signal, os # Imports pour LDAP sys.path.append('/usr/scripts/gestion') from gen_confs import gen_config, anim, cprint, OK, ERREUR -from ldap_crans import crans_ldap, crans, preattr, ldap, smtpserv -from whos import adher_details +from ldap_crans import crans_ldap, preattr, ldap -from socket import gethostname - -if gethostname().split(".")[0] == 'zamok': - # Imports pour mailman +try: sys.path.append('/usr/lib/mailman') from Mailman import MailList from Mailman import Utils from Mailman.UserDesc import UserDesc +except: + # Machine sans mailman, les ML ne seront pas reconfigurées + pass -class droits(crans_ldap,gen_config) : +class droits(gen_config) : + def restart(s) : + # Rien à faire + pass + + def __str__(s): + return "droits" + +class droits_ldap(crans_ldap,droits) : ####### Les groupes base_group_dn = 'ou=Group,dc=crans,dc=org' @@ -38,14 +45,7 @@ class droits(crans_ldap,gen_config) : 'respbats' : [ u'Câbleur', u'Nounou' ], '+moderateurs' : [ u'Modérateur' ], '+disconnect' : [ u'Déconnecteur' ] } - - def restart(s) : - # Rien à faire - pass - - def __str__(self): - return "droits" - + def build_group(self) : """ Reconstruit les groupes dans la base LDAP """ self.anim.iter = len( self.groupes.keys() ) @@ -74,61 +74,6 @@ class droits(crans_ldap,gen_config) : modlist = ldap.modlist.modifyModlist(init_data,data) self.conn.modify_s(dn,modlist) - def build_master_passwd_group(self) : - """Reconstruit les entrées à ajouter dans master.passwd - - Reconstruit également /etc/group pour le group wheel - """ - master = "" - group = "wheel:*:0:root" - self.anim.iter = 2 - for fonction in ("Nounou", "Apprenti"): - self.anim.cycle() - # Qui doit être dans ce groupe ? - res = self.search('droits=%s' % fonction)['adherent'] - for a in res: - if fonction == "Nounou": - # On rajoute à /etc/group - group = "%s,%s" % (group, a._data['uid'][0]) - # On ajoute dans master - # Le mot de passe est bidon - master = "%s%s:$1$rQcJgpD8$ZZjjszWKnSp9rR6iZ9GPm2:%s:1000:ldap:0:0:%s:%s:%s\n" % (master, - a._data['uid'][0], - a._data['uidNumber'][0], - a._data['gecos'][0], - a._data['homeDirectory'][0], - "/bin/zsh") - # On crée le home - try: - os.mkdir("%s" % a._data['homeDirectory'][0]) - except: # Façon Fred - pass - - group = "%s\n" % group - # On va réécrire /etc/master.passwd - # cf man master.passwd - fichier = file("/etc/master.passwd") - for line in fichier: - if line.split(":")[4].strip() != "ldap": - master = "%s%s" % (line,master) - fichier.close() - # On va écrire par-dessus - fichier = file("/etc/master.passwd", "w") - fichier.write(master) - fichier.close() - os.system("pwd_mkdb -p /etc/master.passwd") - - # On réécrit /etc/group - fichier = file("/etc/group") - for line in fichier: - if line.split(":")[0].strip() != "wheel": - group = "%s%s" % (group,line) - fichier.close() - # On va réécrire par-dessus - fichier = file("/etc/group", "w") - fichier.write(group) - fichier.close() - def print_liste(self,poste) : """ Donne la liste des membres actifs """ for adh in self.search('droits=%s&chbre!=EXT' % poste)['adherent'] : @@ -188,65 +133,104 @@ class droits(crans_ldap,gen_config) : self.mlist_to_unlock = None def gen_conf(self) : - if gethostname().split(".")[0] == 'zamok': - self.anim = anim('\tconfiguration groupes') - try : - self.build_group() - self.anim.reinit() - print OK - except : - self.anim.reinit() - print ERREUR - if self.debug : - import traceback - traceback.print_exc() - - self.anim = anim('\tconfiguration ML Crans') - try : - self.sync_ML() - self.anim.reinit() - print OK - except : - self.anim.reinit() - try : - # Au cas où... - self.mlist_to_unlock.Unlock() - except : - pass - print ERREUR - if self.debug : - import traceback - traceback.print_exc() - - self.anim = anim('\tenvoi d\'un mail à roots') - try : - from mail import mail_details - adherents = [] - for uid in self.uids : - adherents += self.search('uid=%s' % uid)['adherent'] - mail_details(adherents, Subject = 'Modification des droits d\'un adherent') - self.anim.reinit() - print OK - except : - self.services_to_restart('droits',self.uids) - self.anim.reinit() - print ERREUR - if self.debug : - import traceback - traceback.print_exc() - - elif gethostname().split(".")[0] == 'nectaris': - self.anim = anim('\tconfiguration master.passwd') + self.anim = anim('\tconfiguration groupes') + try: + self.build_group() + self.anim.reinit() + print OK + except: + self.anim.reinit() + print ERREUR + if self.debug : + import traceback + traceback.print_exc() + + self.anim = anim('\tconfiguration ML Crans') + try: + self.sync_ML() + self.anim.reinit() + print OK + except: + self.anim.reinit() + print ERREUR + if self.debug : + import traceback + traceback.print_exc() try: - self.build_master_passwd_group() - self.anim.reinit() - print OK - except: - self.anim.reinit() - print ERREUR - if self.debug : - import traceback - traceback.print_exc() + # Au cas où... + self.mlist_to_unlock.Unlock() + except : + pass + +class droits_openbsd(droits) : + def build_master_passwd_group(self) : + """Reconstruit les entrées à ajouter dans master.passwd + + Reconstruit également /etc/group pour le group wheel + """ + master = "" + group = "wheel:*:0:root" + self.anim.iter = 2 + for fonction in ("Nounou", "Apprenti"): + self.anim.cycle() + # Qui doit être dans ce groupe ? + res = crans_ldap().search('droits=%s' % fonction)['adherent'] + for a in res: + if fonction == "Nounou": + # On rajoute à /etc/group + group = "%s,%s" % (group, a._data['uid'][0]) + # On ajoute dans master + # Le mot de passe est bidon + master = "%s%s:$1$rQcJgpD8$ZZjjszWKnSp9rR6iZ9GPm2:%s:1000:ldap:0:0:%s:%s:%s\n" % (master, + a._data['uid'][0], + a._data['uidNumber'][0], + a._data['gecos'][0], + a._data['homeDirectory'][0], + "/bin/zsh") + # On crée le home + try: + os.mkdir("%s" % a._data['homeDirectory'][0]) + except: + pass + + group = "%s\n" % group + # On va réécrire /etc/master.passwd + # cf man master.passwd + fichier = file("/etc/master.passwd") + for line in fichier: + if line.split(":")[4].strip() != "ldap": + master = "%s%s" % (line,master) + fichier.close() + # On va écrire par-dessus + fichier = file("/etc/master.passwd", "w") + fichier.write(master) + fichier.close() + os.system("pwd_mkdb -p /etc/master.passwd") + + # On réécrit /etc/group + fichier = file("/etc/group") + for line in fichier: + if line.split(":")[0].strip() != "wheel": + group = "%s%s" % (group,line) + fichier.close() + # On va réécrire par-dessus + fichier = file("/etc/group", "w") + fichier.write(group) + fichier.close() + + def gen_conf(self) : + self.anim = anim('\tconfiguration master.passwd') + try: + self.build_master_passwd_group() + self.anim.reinit() + print OK + except: + self.anim.reinit() + print ERREUR + if self.debug : + import traceback + traceback.print_exc() + if __name__ == '__main__' : if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) == 1 : diff --git a/gestion/gen_confs/firewall.py b/gestion/gen_confs/firewall.py index e3cb4f27..27dc742d 100755 --- a/gestion/gen_confs/firewall.py +++ b/gestion/gen_confs/firewall.py @@ -1,71 +1,916 @@ -#! /usr/bin/env python -# -*- coding: iso-8859-15 -*- - -""" Génération de la configuration pour le firewall +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- +# The authors of this code are +# Manuel Sabban +# Frédéric Pauget +# Mathieu Segaud +# +# Rewritten as inherited classes from firewall_crans +# by Mathieu Segaud +# +# Copyright (c) 2004 Manuel Sabban, Frédéric Pauget +# Copyright (c) 2005 Mathieu Segaud +# +# Permission to use, copy, and modify this software with or without fee +# is hereby granted, provided that this entire notice is included in +# all source code copies of any software which is or includes a copy or +# modification of this software. +# +# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY +# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE +# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR +# PURPOSE. + +import sys +sys.path.append('/usr/scripts/gestion') + +import syslog +import pwd +from lock import * +from ldap_crans import crans_ldap, ann_scol, machine, crans, invite, hostname +from affich_tools import * +from commands import getstatusoutput +from iptools import AddrInNet +syslog.openlog('firewall') + +debug = 1 + +class IptablesError(Exception): + """ Gestion des erreurs d'iptables """ + def __init__(self,cmd,err_code,output): + self.cmd=cmd + self.err_code=err_code + self.output=output + syslog.syslog(syslog.LOG_ERR,"%s : status %s,%s" % (cmd,err_code,output)) + def __str__(self): + return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output) + +def iptables(cmd): + """ Interface d'iptables """ + syslog.syslog(syslog.LOG_INFO,cmd) + status,output=getstatusoutput("/sbin/iptables "+cmd) + if status: + raise IptablesError(cmd,status,output) + return output + + +class firewall_crans : + """ + Classe parente pour les firewalls du crans + Implementee directement a partir du firewall de komaz, initialement + ecrit par Manuel Sabban et Fred Pauget. + + * les méthodes a surcharger pour l'impementation eme des firewall + sont nat_table, filter_table, pour la preparation du fw, + start_fw_funcs pour la mise en place du filtrage. + + * enable_route et disable_route utilisees seulement par komaz + + * serveurs_maj, adh_maj_list_to_do et serveurs_maj_list_to_do, + pour la mise en place de la MAC-IP. + en particulier, adh_maj_list_to_do et serveurs_maj_list_to_do + sont factorisees pour la simple et bonne raison que les sources + de la liste to_do originale ne seront pas forcement identiques + (c'est un peu sale...) + + * La classe parente contient a peu de choses pres tout ce qu'il + faut pour mettre en place un fw basique n'effectuant que la + verif MAC-IP. + """ + zone_serveur="138.231.136.0/28" + vlan_adm="138.231.144.0/28" + + adm_users = [ "root", "identd", "daemon", "postfix", "freerad", "amavis", "nut" ] + + + mac_wifi = '00:0c:f1:fa:f1:4b' + mac_komaz = '00:01:02:b0:31:b6' + + limit = " -m limit --limit 10/s --limit-burst 10 " + log_template = '-m limit --limit 1/s --limit-burst 1 -j LOG --log-level notice --log-prefix ' + filtre_flood = '-m hashlimit --hashlimit 20 --hashlimit-mode srcip --hashlimit-name flood' + + machines = [] + debug = 1 + + def exception_catcher(self,tache) : + """ Exécute la tache founie en gérant les diverses exceptions + pouvant survenir + Retourne 1 en cas d'erreur et 0 sinon """ + try : + tache() + return 0 + except IptablesError, c : + self.anim.reinit() + print ERREUR + if self.debug : print c + except : + self.anim.reinit() + print ERREUR + import traceback + if self.debug : traceback.print_exc() + return 1 + + def __machines(self) : + """ Liste des machines du crans """ + if not self.machines : + self.anim = anim(" Interrogation de la base LDAP") + self.machines = crans_ldap().search('ip=*')['machine'] + print OK + return self.machines + + def __init__(self) : + """ Pose un lock """ + make_lock('firewall') + + def __del__(self) : + """ Destruction du lock """ + # Comprend pas pourquoi il faut réimporter ici -- Fred + from lock import remove_lock + remove_lock('firewall') + + def nat_table(self) : + """ Remplit la table nat """ + return + + def filter_table(self) : + """ Remplit la table filter """ + self.anim = anim(' Structure de la table filter') + print OK + + def filter_table_tweaks(self) : + """ Complete la table filter """ + return + + def start_fw_funcs(self) : + """ Ordonnance la construction du firewall """ + self.exception_catcher(self.test_mac_ip) + + def post_start_hook(self) : + """ Hook de fin de demarrage """ + return + + def pre_stop_hook(self) : + """ Hook de debut d'arret """ + return + + def restart(self): + """ Rédémarrage du firewall """ + cprint('Redémarrage firewall','gras') + self.start(False) + + def start(self,aff_txt_intro=True) : + """ Construction du firewall + aff_txt_intro s'occupe uniquement de l'esthétisme + """ + if aff_txt_intro : cprint('Démarrage firewall','gras') + # Préliminaires + if not self.__machines() or self.exception_catcher(self.__stop) : + cprint("Abandon",'rouge') + return + + # Initialisation + self.exception_catcher(self.nat_table) + self.exception_catcher(self.filter_table) + self.exception_catcher(self.filter_table_tweaks) + + # Remplissage + self.start_fw_funcs() + + # On peux router + self.post_start_hook() + cprint(" -> fin de la procédure de démarrage",'vert') + + def stop(self): + """ Arrête le firewall """ + cprint("Arrêt du firewall",'gras') + self.pre_stop_hook() + self.exception_catcher(self.__stop) + cprint(" -> fin de la procédure d'arrêt",'vert') + + def __stop(self) : + self.anim = anim(" Suppression regles") + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-F") + iptables("-t nat -F") + iptables("-X") + iptables("-t nat -X") + print OK + + + def test_mac_ip(self) : + """ Reconstruit la correspondance MAC-IP des machines des adhérents """ + self.anim = anim(' Chaine TEST_MAC-IP',len(self.__machines())+1) + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -F TEST_MAC-IP") + self.anim.cycle() + + def procedure() : + for machine in self.__machines() : + self.__test_mac_ip(machine) + self.anim.cycle() + iptables("-t nat -P PREROUTING DROP") + self.anim.reinit() + print OK + + self.exception_catcher(procedure) + + + def __test_mac_ip(self,machine): + ip=machine.ip() + mac=machine.mac() + + # FIXME: ceci est loin d'etre efficace + # fascisme: on met les machines du crans en premier + if machine.proprietaire().__class__ == crans: + insert = '-I' + else: + insert = '-A' + if machine.ipsec(): + # Machine wifi, c'est la mac de Nectaris + iptables("-t nat %s TEST_MAC-IP -s "%(insert)+\ + "%s -m mac --mac-source %s -j ACCEPT"%(ip,self.mac_wifi)) + else: + # Machine fixe + iptables("-t nat %s TEST_MAC-IP -s "%(insert)+\ + "%s -m mac --mac-source %s -j ACCEPT"%(ip,mac)) + + def _serveur_maj(self): + pass + + def serveurs_maj_list_to_do(self) : + pass + + def adh_maj_list_to_do(self) : + pass + + def port_maj(self,ip_list) : + """ Mise à jour des ports pour les ip fournies """ + # Note : système bourrin (on efface les chaines et on refait) + # mais rapide et efficace (si qqn veut se casser le cul à + # un système aussi délicat que pour la correspondance MAC-IP...) + # -- Fred + serveur_maj = False + adh_maj = False + for ip in ip_list : + if AddrInNet(ip,self.zone_serveur) : + serveur_maj = True + else : + adh_maj = True + if serveur_maj and adh_maj : + break + to_do=[] + if serveur_maj : + self.exception_catcher(self.serveurs_maj_list_to_do) + + if adh_maj : + self.exception_catcher(self.adh_maj_list_to_do) + + def mac_ip_maj(self,ip_list) : + """ Mise à jour de la correspondance MAC-IP pour les ip fournies """ + ## Que faut-il faire ? + self.anim = anim(' Analyse travail à effectuer') + if ip_list == [''] : + print OK + ' (rien à faire)' + return + + mac_ip_maj = {} + serveur_maj = False + for ip in ip_list : + machine = crans_ldap().search('ip=%s'% ip)['machine'] + if not machine : + # Destruction des occurences + if AddrInNet(ip,self.zone_serveur) : + serveur_maj = True + else : + mac_ip_maj[ip] = None + + elif len(machine) == 1 : + # Mise à jour de la machine + if AddrInNet(ip,self.zone_serveur) : + serveur_maj = True + else : + # Il faut avoir payé ou être une machine du crans ou un invite + if crans_ldap().search('paiement=ok&ip=%s'% ip)['machine'] or \ + machine[0].proprietaire().__class__ == crans or \ + machine[0].proprietaire().__class__ == invite : + mac_ip_maj[ip] = machine[0] + else : + mac_ip_maj[ip] = None + else : + print WARNING + if debug : + sys.stderr.write("Plusieurs machines avec l'IP %s\n" % ip) + + print OK + + ## Traitement + # Serveurs + if serveur_maj : + self._serveur_maj() + + # Correspondance MAC-IP + if mac_ip_maj or serveur_maj : + def procedure() : + warn = '' + self.anim = anim(' Actualisation TEST_MAC-IP') + for regle in iptables("-t nat -L TEST_MAC-IP -n").split('\n')[2:] : + regle = regle.split() + ip = regle[3] + mac = regle[6].lower() + if ip in mac_ip_maj.keys() : + # La règle correspond à une ip à mettre à jour + machine = mac_ip_maj[ip] + try : + if not machine : + # Il faut détruire cette entrée + iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j ACCEPT" % (ip, mac)) + else : + if ( machine.ipsec() and mac!=self.mac_wifi ) \ + or ( not machine.ipsec() and mac != machine.mac() ) : + # La correspondance MAC-IP est fausse => on ajoute la bonne règle + self.__test_mac_ip(machine) + # Supression de l'ancienne ligne + iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j ACCEPT" % (ip, mac)) + + # Toutes les autres occurences devront être détruites + mac_ip_maj[ip]=None + + + except IptablesError, c : + warn += c + + # Ajout des machines qui n'étaient pas dans le firewall + for machine in mac_ip_maj.values() : + if machine : + self.__test_mac_ip(machine) + if warn : + print WARNING + sys.stdout.write(warn) + else : + print OK + + self.exception_catcher(procedure) + + def build_chaine_adherent(self,chaine,methode) : + # On construit d'abord les autorisations particuli\uffffres + if not self.build_chaine(chaine, methode) : + # Puis si pas de problèmes les autorisations par défaut + self.anim.reinit() + for proto in [ 'tcp' , 'udp' ] : + for port in self.ports_default["%s_%s" % ( proto, chaine) ] : + self.anim.cycle() + iptables("-I %s -p %s --dport %s -j ACCEPT" % (chaine, proto,port) ) + self.anim.reinit() + print OK + + def build_chaine(self,chaine, methode) : + self.anim = anim(' Chaîne %s' % chaine,len(self.__machines())+1) + iptables("-F %s" % chaine) + self.anim.cycle() + def procedure() : + for machine in self.__machines() : + methode(machine) + self.anim.cycle() + iptables("-A %s -j REJECT" % chaine) + return self.exception_catcher(procedure) -Copyright (C) Frédéric Pauget -Licence : GPLv2 """ - -from gen_confs import gen_config -from ldap_crans import crans_ldap -from time import localtime - -class firewall(gen_config) : - """ Génère le fichier de paires MAC-IP """ - # Fichier - MACIP = '/CRANS/generated/ether/pairesMAC-IP.txt' +Komaz +""" - restart_cmd = '/etc/init.d/firewall macip' +class firewall_komaz(firewall_crans) : + """ + Structure du firewall : + table nat : + PREROUTING (policy par defaut : DROP) + 1) passage par TEST_VIRUS_FLOOD pour tout ce qui n'est pas dans zone_serveur + 2) passage dans RESEAUX_NON_ROUTABLES_DST + 3) passage est paquets venant de l'extérieur dans RESEAUX_NON_ROUTABLES_SRC + 4) on laisse passer vers filter les paquets suivants : + source ou destination les serveurs de serveurs_crans + ce qui vient de l'extérieur + 5) passage par TEST_MAC-IP + + TEST_VIRUS_FLOOD droppe les paquets contenant des virus ou les paquets de flood + RESEAUX_NON_ROUTABLES_DST droppe les paquets dont la destination est non routable + RESEAUX_NON_ROUTABLES_SRC droppe les paquets dont la source est non routable + TEST_MAC-IP envoi les bon paquets vers CRANS_VERS_EXT + + table filter : + FORWARD (policy par defaut : ACCEPT) + 1) passage par BLACKLIST + 2) passage pas FILTRE_P2P (REJECT sur tout le trafic p2p) + 3) ce qui a pour source les serveurs de serveurs_crans est dirigé vers SERVEURS_VERS_EXT + 4) ce qui a pour destination les serveurs de serveurs_crans est dirigé EXT_VERS_SERVEURS + 5) tout ce qui vient de l'interface externe est dirigé vers EXT_VERS_CRANS + 6) ce qui a pour source les serveurs de serveurs_crans est dirigé vers EXT_VERS_CRANS + + BLACKLIST fitre des ip blacklistées (reject) + FILTRE_P2P filtre le traffic de p2p + EXT_VERS_CRANS et CRANS_VERS_EXT + ACCEPT pour les paquets vers les machines du crans (test port-ip) + REJECT pour le reste + EXT_VERS_SERVEURS et SERVEURS_VERS_EXT + ACCEPT pour bon mac-ip-port + REJECT pour le reste + """ + + # interfaces physiques + eth_ext = "eth2" + eth_int = "eth0" - def __str__(self) : - return "firewall" - - def _gen(self) : - macip= self._open_conf(self.MACIP) - - self.anim.iter=len(self.machines) - for machine in self.machines : - self.anim.cycle() - macip.write( "%s %s\n" % ( machine.mac(), machine.ip() ) ) - - macip.close() - -class bl_upload_fw(gen_config) : - """ Génère le fichier de blackliste d'upload pour le firewall""" - # Fichier - BL_UPLOAD = '/CRANS/confs/blacklist.cf' - - restart_cmd = '/etc/init.d/firewall blacklist' + # Ports ouverts + ports_default = { 'tcp_EXT_VERS_CRANS' : [ '22' ], + 'tcp_CRANS_VERS_EXT': [ ':79', '81:134', '136', '140:444', '446:'], + 'udp_EXT_VERS_CRANS' : [ ], + 'udp_CRANS_VERS_EXT': [ ':136','140:'] } - def __str__(self) : - return "blackliste upload firewall" + + ports_virus = { 'tcp' : [ 135, 445 ] , 'udp' : [] } + + # Filtrage du peer to peer + filtres_p2p = [ ('bit', 'Bittorrent'), + ('apple', 'AppleJuice'), + ('soul', 'SoulSeek'), + ('winmx', 'WinMX'), + ('edk', 'eDonkey'), + ('dc', 'DirectConnect'), + ('kazaa', 'KaZaa'), + ('ares', 'Ares'), + ('gnu', 'GNUtella') ] + ports_p2p = [ '412', '1214', '4662:4665' , '6346:6347', '6699', '6881:6889' ] - def _gen(self) : - db = crans_ldap() - upload = self._open_conf( self.BL_UPLOAD, '#' ) - base = db.search('paiement=ok&blacklist=*upload*') - liste = base['adherent'] + base['club'] - self.anim.iter=len(liste) - for adh in liste : - self.anim.cycle() - for machine in adh.machines() : - bl = machine.blacklist_all() - # 0 = présent, 1 = passé - for i in range(0,2): - # Si on est dans le passé, on commente la ligne - if i == 1: - commentaire = '#' - else: - commentaire = '' - # On regarde s'il y a une sanction d'upload - if 'upload' in bl[i]: - # Si on est dans le présent et que le type est bloqué, il n'existe plus - if i == 1 or not 'bloq' in bl[i] : - # Pour chaque sanction d'upload, on va écrire une ligne : - for sanction in bl[i]['upload']: - upload.write( '%s%s:smtp,smtps,pop3,pop3s,imap,imaps,http # %s:%s:upload\n' % (commentaire, - machine.nom(), - sanction[0].split(" ")[0], - sanction[1].split(" ")[0])) - upload.close() + liste_reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12', + '169.254.0.0/16', '192.168.0.0/16', '224.0.0.0/4'] + + def reseaux_non_routables(self) : + """ Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """ + self.anim = anim(' Filtrage ip non routables',len(self.liste_reseaux_non_routables)) + for reseau in self.liste_reseaux_non_routables : + iptables("-t nat -A RESEAUX_NON_ROUTABLES_DST -d %s -j DROP" % reseau) + iptables("-t nat -A RESEAUX_NON_ROUTABLES_SRC -s %s -j DROP" % reseau) + self.anim.cycle() + self.anim.reinit() + print OK + + def nat_table(self) : + self.anim = anim(' Structure de la table nat') + for chaine in [ 'TEST_MAC-IP', 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST', 'TEST_VIRUS_FLOOD', 'LOG_VIRUS', 'LOG_FLOOD' ] : + iptables('-t nat -N %s' % chaine) + + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -A PREROUTING -i lo -j ACCEPT") + iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP") + iptables("-t nat -A PREROUTING -s ! %s -j TEST_VIRUS_FLOOD" % self.zone_serveur) + iptables("-t nat -A PREROUTING -j RESEAUX_NON_ROUTABLES_DST") + iptables("-t nat -A PREROUTING -i %s -j RESEAUX_NON_ROUTABLES_SRC" % self.eth_ext ) + iptables("-t nat -A PREROUTING -i %s -j ACCEPT" % self.eth_ext ) + iptables("-t nat -A PREROUTING -s %s -j ACCEPT" % self.zone_serveur ) + iptables("-t nat -A PREROUTING -d %s -j ACCEPT" % self.zone_serveur ) + iptables("-t nat -A PREROUTING -j TEST_MAC-IP") + iptables("-t nat -P PREROUTING DROP") + iptables("-t nat -P OUTPUT ACCEPT") + print OK + + def filter_table_tweaks(self) : + self.anim = anim(' règles spécifiques à komaz') + for chaine in [ 'ADMIN_VLAN', 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS', 'CRANS_VERS_EXT', 'BLACKLIST_SRC', 'BLACKLIST_DST' , 'FILTRE_P2P' ] : + iptables('-N %s' % chaine) + iptables("-A FORWARD -i lo -j ACCEPT") + iptables("-A FORWARD -p icmp -j ACCEPT") + iptables("-A FORWARD -i %s -d %s -j REJECT" % (self.eth_ext, self.vlan_adm) ) + iptables("-A FORWARD -i %s -j BLACKLIST_DST" % self.eth_ext ) + iptables("-A FORWARD -o %s -j BLACKLIST_SRC" % self.eth_ext ) + iptables("-A FORWARD -s ! %s -d ! %s -j FILTRE_P2P" % (self.zone_serveur, self.zone_serveur) ) + iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT") + iptables("-A FORWARD -i %s -d %s -j ADMIN_VLAN" % (self.eth_int, self.vlan_adm) ) + iptables("-A FORWARD -i %s -d %s -j EXT_VERS_SERVEURS" % (self.eth_ext, self.zone_serveur) ) + iptables("-A FORWARD -o %s -s %s -j SERVEURS_VERS_EXT" % (self.eth_ext, self.zone_serveur) ) + iptables("-A FORWARD -i %s -j EXT_VERS_CRANS" % self.eth_ext ) + iptables("-A FORWARD -o %s -j CRANS_VERS_EXT" % self.eth_ext ) + print OK + + def post_start_hook(self) : + self.anim = anim(" Mise en place routage") + warn = '' + for cmd in [ 'echo 1 > /proc/sys/net/ipv4/ip_forward' , + 'echo 65536 > /proc/sys/net/ipv4/ip_conntrack_max' , + 'modprobe ip_conntrack_ftp' , + 'modprobe ip_conntrack_irc' ] : + status,output=getstatusoutput(cmd) + if status : + warn += output + '\n' + if warn : + print WARNING + if self.debug : + print warn + else : + print OK + + def pre_stop_hook(self) : + self.anim = anim(" Arret routage") + status,output=getstatusoutput('echo 0 > /proc/sys/net/ipv4/ip_forward') + if status : + print ERREUR + else : + print OK + + def start_fw_funcs(self) : + self.exception_catcher(self.log_chaines) + self.exception_catcher(self.test_virus_flood) + self.exception_catcher(self.reseaux_non_routables) + self.exception_catcher(self.blacklist) + self.exception_catcher(self.admin_vlan) + self.exception_catcher(self.serveurs_vers_ext) + self.exception_catcher(self.ext_vers_serveurs) + self.exception_catcher(self.crans_vers_ext) + self.exception_catcher(self.ext_vers_crans) + self.exception_catcher(self.test_mac_ip) + self.exception_catcher(self.filtre_p2p) + + def serveurs_maj_list_to_do(self) : + self.exception_catcher(self.serveurs_vers_ext) + self.exception_catcher(self.ext_vers_serveurs) + + def adh_maj_list_to_do(self) : + self.exception_catcher(self.crans_vers_ext) + self.exception_catcher(self.ext_vers_crans) + + def log_chaines(self) : + """ Construction des chaines de log (LOG_VIRUS et LOG_FLOOD) """ + self.anim = anim(' Création des chaines de log') + for filtre in [ 'VIRUS', 'FLOOD' ] : + # Vidage de la chaîne + iptables('-t nat -F LOG_%s' % filtre) + iptables('-t nat -A LOG_%s %s %s:' % (filtre, self.log_template, filtre.capitalize()) ) + iptables('-t nat -A LOG_%s -j DROP' % filtre ) + self.anim.cycle() + self.anim.reinit() + print OK + + def test_virus_flood(self) : + """ Construction de la chaîne TEST_VIRUS """ + iptables('-t nat -F TEST_VIRUS_FLOOD') + self.anim = anim(' Filtrage virus et floods') + + for proto, ports in self.ports_virus.items() : + for port in ports : + iptables('-t nat -A TEST_VIRUS_FLOOD -p %s --dport %s -j LOG_VIRUS' % (proto, port) ) + self.anim.cycle() + + iptables('-t nat -A TEST_VIRUS_FLOOD %s -j RETURN' % self.filtre_flood) # Les limites en négatif ca ne marche pas. + self.anim.cycle() + iptables('-t nat -A TEST_VIRUS_FLOOD -j LOG_FLOOD') + self.anim.reinit() + print OK + + def serveurs_vers_ext(self) : + """ Reconstruit la chaine SERVEURS_VERS_EXT """ + if not self.build_chaine('SERVEURS_VERS_EXT', self.__serveurs_vers_ext) : + self.anim.reinit() + print OK + + def ext_vers_serveurs(self) : + """ Reconstruit la chaine EXT_VERS_SERVEURS """ + if not self.build_chaine('EXT_VERS_SERVEURS', self.__ext_vers_serveurs) : + self.anim.reinit() + print OK + + def crans_vers_ext(self) : + """ Reconstruit la chaine CRANS_VERS_EXT """ + self.build_chaine_adherent('CRANS_VERS_EXT',self.__crans_vers_ext) + + def ext_vers_crans(self) : + """ Reconstruit la chaine EXT_VERS_CRANS """ + self.build_chaine_adherent('EXT_VERS_CRANS',self.__ext_vers_crans) + + def admin_vlan(self) : + """ Reconstruit la chaine ADMIN_VLAN """ + iptables("-F ADMIN_VLAN") + nounou_machines = [] + for adherent in crans_ldap().search('droits=Nounou')['adherent'] : + for machine in adherent.machines() : + nounou_machines.append(machine.ip()) + + iptables("-A ADMIN_VLAN -j REJECT") + self.anim = anim(' Chaîne ADMIN_VLAN', len(nounou_machines)) + for machine in nounou_machines : + self.anim.cycle() + iptables("-I ADMIN_VLAN -p tcp -s %s --dport ssh -j ACCEPT" % machine) + self.anim.reinit() + print OK + + def __serveurs_vers_ext(self,machine): + ip=machine.ip() + if not AddrInNet(ip,self.zone_serveur): + # C'est une machine adhérent, rien à faire ici + return + + mac = machine.mac() + ports = { 'tcp' : machine.portTCPout(), + 'udp' : machine.portUDPout() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto].split() : + iptables("-I SERVEURS_VERS_EXT -s %s -p %s --dport %s -m mac --mac-source %s -j ACCEPT" \ + %(ip,proto,port,mac)) + + def __ext_vers_serveurs(self,machine): + ip=machine.ip() + if not AddrInNet(ip,self.zone_serveur): + # C'est une machine adhérent, rien à faire ici + return + + ports = { 'tcp' : machine.portTCPin(), + 'udp' : machine.portUDPin() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto].split() : + iptables("-I EXT_VERS_SERVEURS -d %s -p %s --dport %s -j ACCEPT"\ + %(ip,proto,port)) + + def __crans_vers_ext(self,machine): + ip=machine.ip() + if AddrInNet(ip,self.zone_serveur): + # C'est un serveur, rien à faire ici + return + + ports = { 'tcp' : machine.portTCPout(), + 'udp' : machine.portUDPout() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto].split() : + iptables("-I CRANS_VERS_EXT -s %s -p %s --dport %s -j ACCEPT" \ + %(ip,proto,port)) + + def __ext_vers_crans(self,machine): + ip=machine.ip() + if AddrInNet(ip,self.zone_serveur): + # C'est un serveur, rien à faire ici + return + + ports = { 'tcp' : machine.portTCPin(), + 'udp' : machine.portUDPin() } + + for proto in [ 'tcp', 'udp' ] : + for port in ports[proto].split() : + """ FIXME: bug dans la base ldap """ + if ip == '138.231.141.26': + for fixed_port in port.split(','): + iptables("-I EXT_VERS_CRANS -d %s -p %s --dport %s -j ACCEPT" \ + %(ip,proto,fixed_port)) + continue + + iptables("-I EXT_VERS_CRANS -d %s -p %s --dport %s -j ACCEPT" \ + %(ip,proto,port)) + + def blacklist(self): + """ Construit les chaines de blackliste (BLACKLIST_{DST,SRC}) """ + self.anim = anim(" Blackliste") + iptables('-F BLACKLIST_DST') + iptables('-F BLACKLIST_SRC') + + blacklist=[] + search = crans_ldap().search('blacklist=*&paiement=%s'% ann_scol) + for entite in search['adherent']+search['club']+search['machine']: + self.anim.cycle() + sanctions = entite.blacklist_actif() + if 'upload' in sanctions or 'warez' in sanctions : + from ldap_crans import machine + if entite.__class__ == machine: + blacklist+=[entite] + else: + blacklist+=entite.machines() + + for machine in blacklist: + iptables("-A BLACKLIST_DST -d %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip()) + iptables("-A BLACKLIST_SRC -s %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip()) + + self.anim.reinit() + print OK + + def filtre_p2p(self): + """ Construit la chaines de filtrage du p2p (FILTRE_P2P) """ + self.anim = anim(" Filtrage p2p") + iptables('-F FILTRE_P2P') + + # On ne filtre que ce qui passe sur l'interface externe + iptables('-A FILTRE_P2P -i %s -o %s -j RETURN' % (self.eth_int, self.eth_int) ) + + for port in self.ports_p2p : + iptables('-A FILTRE_P2P -p tcp --dport %s -j REJECT --reject-with icmp-admin-prohibited' % port ) + iptables('-A FILTRE_P2P -p udp --dport %s -j REJECT --reject-with icmp-admin-prohibited' % port ) + self.anim.cycle() + + for filtre in self.filtres_p2p : + iptables('-A FILTRE_P2P -m ipp2p --%s -j LOG --log-prefix "IPP2P=%s "' % (filtre[0], + filtre[1])) + iptables('-A FILTRE_P2P -m ipp2p --%s -j REJECT --reject-with icmp-admin-prohibited' % filtre[0]) + self.anim.cycle() + + self.anim.reinit() + print OK + + def serveurs_maj(self) : + self.exception_catcher(self.serveurs_vers_ext) + +""" +Bleu +""" + +class firewall_bleu(firewall_crans) : + """ + Structure du firewall : + table nat : + SERV_OUT_ADM + TEST_MAC-IP + table filter : + FORWARD (policy par defaut : DROP) + rien ne passe pas la chaine FORWARD + INPUT (policy par defaut : ACCEPT pour l'instant) + + """ + + # interfaces physiques + eth_pub = "eth0" + eth_adm = "eth0.2" + + def serv_out_adm(self) : + self.anim = anim(' Output vers VLAN adm', len(self.adm_users)) + for user in self.adm_users : + self.anim.cycle() + try: + iptables("-A SERV_OUT_ADM -m owner --uid-owner %d -j ACCEPT" % pwd.getpwnam(user)[2]) + except KeyError: + continue + + iptables("-A SERV_OUT_ADM -p tcp --dport ldap -j ACCEPT") + iptables("-A SERV_OUT_ADM -j DROP") + self.anim.reinit() + print OK + + def nat_table(self) : + self.anim = anim(' Structure de la table nat') + iptables('-t nat -N TEST_MAC-IP') + iptables('-t filter -N SERV_OUT_ADM') + + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -A PREROUTING -i lo -j ACCEPT") + iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP") + + iptables("-t nat -A PREROUTING -s 138.231.136.0/21 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.144.0/24 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.148.0/22 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -m mac --mac-source %s -j ACCEPT" + % (self.mac_komaz)) + iptables("-t filter -A OUTPUT -o lo -j ACCEPT") + + # pour une connection entrante venant du VLAN adm, il faut que le ACK + # puisse passer (interaction avec pam, uid de l'utilisateur en OUTPUT) + # on accepte donc les paquets si la connection est + # en RELATED et ESTABLISHED + iptables("-t filter -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT") + iptables("-t filter -A OUTPUT -o %s -j SERV_OUT_ADM" % self.eth_adm) + + iptables("-t nat -P PREROUTING DROP") + iptables("-t filter -P OUTPUT ACCEPT") + print OK + + def start_fw_funcs(self) : + self.exception_catcher(self.test_mac_ip) + self.serv_out_adm() + + def filter_table_tweaks(self) : + self.anim = anim(' regles specifiques a bleu') + iptables("-P INPUT ACCEPT") + iptables("-P FORWARD DROP") + print OK + +""" +Rouge +""" + +class firewall_rouge(firewall_crans) : + """ + Structure du firewall : + table nat : + SERV_OUT_ADM + TEST_MAC-IP + table filter : + FORWARD (policy par defaut : DROP) + rien ne passe pas la chaine FORWARD + INPUT (policy par defaut : ACCEPT pour l'instant) + + """ + + # interfaces physiques + eth_pub = "eth0" + eth_adm = "eth0.2" + + def nat_table(self) : + self.anim = anim(' Structure de la table nat') + iptables('-t nat -N TEST_MAC-IP') + + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -A PREROUTING -i lo -j ACCEPT") + iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP") + + iptables("-t nat -A PREROUTING -s 138.231.136.0/21 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.144.0/24 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.148.0/22 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -m mac --mac-source %s -j ACCEPT" + % (self.mac_komaz)) + + iptables("-t nat -P PREROUTING DROP") + iptables("-t nat -P OUTPUT ACCEPT") + print OK + + def filter_table_tweaks(self) : + self.anim = anim(' regles specifiques a rouge') + iptables("-P INPUT ACCEPT") + iptables("-P FORWARD DROP") + print OK + + +""" +Vert +""" + +class firewall_vert(firewall_crans) : + """ + Structure du firewall : + table nat : + MAC-IP + table filter : + FORWARD (policy par defaut : DROP) + rien ne passe pas la chaine FORWARD + INPUT (policy par defaut : ACCEPT pour l'instant) + + """ + + # interfaces physiques + eth_pub = "eth0" + + def nat_table(self) : + self.anim = anim(' Structure de la table nat') + iptables('-t nat -N TEST_MAC-IP') + + iptables("-t nat -P PREROUTING ACCEPT") + iptables("-t nat -A PREROUTING -i lo -j ACCEPT") + iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP") + + iptables("-t nat -A PREROUTING -s 138.231.136.0/21 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.144.0/24 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -s 138.231.148.0/22 -j TEST_MAC-IP") + iptables("-t nat -A PREROUTING -m mac --mac-source %s -j ACCEPT" + % (self.mac_komaz)) + + iptables("-t nat -P PREROUTING DROP") + iptables("-t nat -P OUTPUT ACCEPT") + print OK + + def filter_table_tweaks(self) : + self.anim = anim(' regles specifiques a vert') + iptables("-P INPUT ACCEPT") + iptables("-P FORWARD DROP") + print OK + +firewall_sila = firewall_rouge +firewall_zamok = firewall_bleu + +if __name__ == '__main__' : + # Chaines pouvant être recontruites + fw = eval('firewall_%s()' % hostname) + chaines = [] + for nom in dir(fw) : + if nom in [ 'log_chaines' , 'test_virus_flood', 'reseaux_non_routables', 'test_mac_ip' , 'blacklist' , 'ext_vers_serveurs' , 'serveurs_vers_ext', 'ext_vers_crans', 'crans_vers_ext' , 'filtre_p2p', 'admin_vlan' ] : + chaines.append(nom) + + def __usage(txt=None) : + if txt!=None : cprint(txt,'gras') + + print """Usage: + %(p)s start : Construction du firewall. + %(p)s restart : Reconstruction du firewall. + %(p)s stop : Arrêt du firewall. + %(p)s : reconstruit les chaines +Les chaines pouvant être reconstruites sont : + %(chaines)s +Pour reconfiguration d'IPs particulières, utiliser generate. """ % \ +{ 'p' : sys.argv[0].split('/')[-1] , 'chaines' : '\n '.join(chaines) } + sys.exit(-1) + + # Bons arguments ? + if len(sys.argv) == 1 : + __usage() + for arg in sys.argv[1:] : + if arg in [ 'stop', 'restart', 'start' ] and len(sys.argv) != 2 : + __usage("L'argument %s ne peut être employé que seul." % arg) + + if arg not in [ 'stop', 'restart', 'start' ] + chaines : + __usage("L'argument %s est inconnu." % arg) + + for arg in sys.argv[1:] : + eval('fw.%s()' % arg ) diff --git a/gestion/gen_confs/firewall_bleu.py b/gestion/gen_confs/firewall_bleu.py deleted file mode 100755 index 9b716651..00000000 --- a/gestion/gen_confs/firewall_bleu.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -# The authors of this code are -# Manuel Sabban -# Frédéric Pauget -# -# Rewritten as an inherited class from firewallÃ_crans -# by Mathieu Segaud -# -# Copyright (c) 2004 Manuel Sabban, Frédéric Pauget -# Copyright (c) 2005 Mathieu Segaud -# -# Permission to use, copy, and modify this software with or without fee -# is hereby granted, provided that this entire notice is included in -# all source code copies of any software which is or includes a copy or -# modification of this software. -# -# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR -# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY -# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE -# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR -# PURPOSE. -""" Firewall de Bleu """ -import sys -sys.path.append('/usr/scripts/gestion') - -import syslog -from firewall_crans import firewall_crans, IptablesError, iptables -from lock import * -from ldap_crans import crans_ldap, ann_scol, machine, crans, invite -from affich_tools import * -from commands import getstatusoutput -from iptools import AddrInNet -syslog.openlog('firewall') - -class firewall_bleu(firewall_crans) : - """ - Structure du firewall : - table nat : - rien pour l'instant - table filter : - FORWARD (policy par defaut : DROP) - rien ne passe pas la chaine FORWARD - INPUT (policy par defaut : ACCEPT pour l'instant) - - """ - - # interfaces physiques - eth_pub = "eth0" - eth_adm = "eth0.2" - - debug = 1 - - def nat_table_tweaks(self) : - self.anim = anim(' règles spécifiques à bleu') - iptables("-t nat -I PREROUTING 6 -d %s -j ACCEPT" % self.zone_serveur ) - iptables("-t nat -I PREROUTING 7 -i %s -j ACCEPT" % self.eth_pub ) - print OK - - def filter_table_tweaks(self) : - self.anim = anim(' règles spécifiques à bleu') - iptables("-P INPUT ACCEPT") - iptables("-P FORWARD DROP") - print OK - - def enable_route(self) : - return - - def disable_route(self) : - return - - def start_fw_funcs(self) : - self.exception_catcher(self.test_mac_ip) - self.exception_catcher(self.serv_out_adm) - - def serveurs_maj_list_to_do(self) : - return - - def adh_maj_list_to_do(self) : - return - - def serveurs_maj(self) : - return - - - - -if __name__ == '__main__' : - # Chaines pouvant être recontruites - global chaines - chaines = [ 'reseaux_non_routables', 'test_mac_ip' ] - - def __usage(txt=None) : - if txt!=None : cprint(txt,'gras') - - print """Usage: - %(p)s start : Construction du firewall. - %(p)s restart : Reconstruction du firewall. - %(p)s stop : Arrêt du firewall. - %(p)s chaine : reconstruit les chaines -Les chaines pouvant être reconstruites sont : - %(chaines)s -Pour reconfiguration d'IPs particulières, utiliser generate. """ % \ -{ 'p' : sys.argv[0].split('/')[-1] , 'chaines' : '\n '.join(chaines) } - sys.exit(-1) - - # Bons arguments ? - if len(sys.argv) == 1 : - __usage() - for arg in sys.argv[1:] : - if arg in [ 'stop', 'restart', 'start' ] and len(sys.argv) != 2 : - __usage("L'argument %s ne peut être employé que seul." % arg) - - if arg not in [ 'stop', 'restart', 'start' ] + chaines : - __usage("L'argument %s est inconnu." % arg) - - fw = firewall_bleu() - for arg in sys.argv[1:] : - eval('fw.%s()' % arg) diff --git a/gestion/gen_confs/firewall_crans.py b/gestion/gen_confs/firewall_crans.py deleted file mode 100755 index f09f315d..00000000 --- a/gestion/gen_confs/firewall_crans.py +++ /dev/null @@ -1,423 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -# The authors of this code are -# Manuel Sabban -# Frédéric Pauget -# -# Copyright (c) 2004 Manuel Sabban, Frédéric Pauget -# Copyright (c) 2005 Mathieu Segaud -# -# Permission to use, copy, and modify this software with or without fee -# is hereby granted, provided that this entire notice is included in -# all source code copies of any software which is or includes a copy or -# modification of this software. -# -# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR -# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY -# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE -# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR -# PURPOSE. -""" Firewalls du Cr@ns """ -import sys -sys.path.append('/usr/scripts/gestion') - -import syslog -import pwd -from lock import * -from ldap_crans import crans_ldap, ann_scol, machine, crans, invite -from affich_tools import * -from commands import getstatusoutput -from iptools import AddrInNet -syslog.openlog('firewall') - -class IptablesError(Exception): - """ Gestion des erreurs d'iptables """ - def __init__(self,cmd,err_code,output): - self.cmd=cmd - self.err_code=err_code - self.output=output - syslog.syslog(syslog.LOG_ERR,"%s : status %s,%s" % (cmd,err_code,output)) - def __str__(self): - return "%s\n status : %s\n %s" % (self.cmd,self.err_code,self.output) - -def iptables(cmd): - """ Interface à iptables """ - syslog.syslog(syslog.LOG_INFO,cmd) - status,output=getstatusoutput("/sbin/iptables "+cmd) - if status: - raise IptablesError(cmd,status,output) - return output - -class firewall_crans : - """ - Classe parente pour les firewalls du crans - Implementee directement a partir du firewall de komaz, initialement - ecrit par Manu Sabban et Fred Pauget. - - * les méthodes à surcharger pour l'implémentation même des firewall - sont nat_table, filter_table, pour la preparation du fw, - start_fw_funcs pour la mise en place du filtrage. - - * enable_route et disable_route utilisees seulement par komaz - - * serveurs_maj, adh_maj_list_to_do et serveurs_maj_list_to_do, - pour la mise en place de la MAC-IP. - en particulier, adh_maj_list_to_do et serveurs_maj_list_to_do - sont factorisees pour la simple et bonne raison que les sources - de la liste to_do originale ne seront pas forcement identiques - (c'est un peu sale...) - - * La classe parente contient a peu de choses pres tout ce qu'il - faut pour mettre en place un fw basique n'effectuant que la - verif MAC-IP. - """ - zone_serveur="138.231.136.0/28" - vlan_adm="138.231.144.0/28" - - adm_users = [ "root", "identd", "daemon", "postfix", "freerad", "clamav", "amavis" ] - - - mac_wifi = '00:0c:f1:fa:f1:4b' - - limit = " -m limit --limit 10/s --limit-burst 10 " - log_template = '-m limit --limit 1/s --limit-burst 1 -j LOG --log-level notice --log-prefix ' - filtre_flood = '-m hashlimit --hashlimit 20 --hashlimit-mode srcip --hashlimit-name flood' - - liste_reseaux_non_routables = [ '10.0.0.0/8', '172.16.0.0/12', - '169.254.0.0/16', '192.168.0.0/16' , '224.0.0.0/4' ] - - machines = [] - debug = 1 - - def exception_catcher(self,tache) : - """ Exécute la tache founie en gérant les diverses exceptions - pouvant survenir - Retourne 1 en cas d'erreur et 0 sinon """ - try : - tache() - return 0 - except IptablesError, c : - self.anim.reinit() - print ERREUR - if self.debug : print c - except : - self.anim.reinit() - print ERREUR - import traceback - if self.debug : traceback.print_exc() - return 1 - - def __machines(self) : - """ Liste des machines du crans """ - if not self.machines : - self.anim = anim(" Interrogation de la base LDAP") - self.machines = crans_ldap().search('ip=*')['machine'] - print OK - return self.machines - - def __init__(self) : - """ Pose un lock """ - make_lock('firewall') - - def __del__(self) : - """ Destruction du lock """ - remove_lock('firewall') - - def nat_table(self) : - self.anim = anim(' Structure de la table nat') - for chaine in [ 'TEST_MAC-IP', 'RESEAUX_NON_ROUTABLES_SRC', 'RESEAUX_NON_ROUTABLES_DST', 'SERV_OUT_ADM' ] : - iptables('-t nat -N %s' % chaine) - - iptables("-t nat -P PREROUTING ACCEPT") - iptables("-t nat -A PREROUTING -i lo -j ACCEPT") - iptables("-t nat -A PREROUTING -d 224.0.0.0/4 -j DROP") - iptables("-t nat -A PREROUTING -j RESEAUX_NON_ROUTABLES_DST") - iptables("-t nat -A PREROUTING -j RESEAUX_NON_ROUTABLES_SRC") - iptables("-t nat -A PREROUTING -j TEST_MAC-IP") - iptables("-t nat -A OUTPUT -d %s -j SERV_OUT_ADM" % self.vlan_adm) - iptables("-t nat -P PREROUTING DROP") - iptables("-t nat -P OUTPUT ACCEPT") - print OK - - def nat_table_tweaks(self) : - return - - def filter_table(self) : - self.anim = anim(' Structure de la table filter') - print OK - - def filter_table_tweaks(self) : - return - - def start_fw_funcs(self) : - self.exception_catcher(self.reseaux_non_routables) - self.exception_catcher(self.test_mac_ip) - self.exception_catcher(self.serv_out_adm) - return - - def enable_route(self) : - return - - def disable_route(self) : - return - - def restart(self): - """ Rédémarrage du firewall """ - cprint('Redémarrage firewall','gras') - self.exception_catcher(self.__stop) - self.start(False) - - def start(self,aff_txt_intro=True) : - """ Construction du firewall - aff_txt_intro s'occupe uniquement de l'esthétisme - """ - if aff_txt_intro : cprint('Démarrage firewall','gras') - # Préliminaires - if not self.__machines() or self.exception_catcher(self.__stop) : - cprint("Abandon",'rouge') - return - - # Initialisation - self.exception_catcher(self.__start) - - # Remplisage - self.start_fw_funcs() - - # On peux router - self.enable_route() - cprint(" -> fin de la procédure de démarrage",'vert') - - def __start(self) : - self.nat_table() - self.nat_table_tweaks() - self.filter_table() - self.filter_table_tweaks() - - def reseaux_non_routables(self) : - """ Construction de RESEAUX_NON_ROUTABLES_{DST,SRC} """ - self.anim = anim(' Filtrage ip non routables',len(self.liste_reseaux_non_routables)) - for reseau in self.liste_reseaux_non_routables : - iptables("-t nat -A RESEAUX_NON_ROUTABLES_DST -d %s -j DROP" % reseau) - iptables("-t nat -A RESEAUX_NON_ROUTABLES_SRC -s %s -j DROP" % reseau) - self.anim.cycle() - self.anim.reinit() - print OK - - def stop(self): - """ Arrête le firewall """ - cprint("Arrêt du firewall",'gras') - self.disable_route() - self.exception_catcher(self.__stop) - cprint(" -> fin de la procédure d'arrêt",'vert') - - def __stop(self) : - self.anim = anim(" Suppression règles") - iptables("-t nat -P PREROUTING ACCEPT") - iptables("-F") - iptables("-t nat -F") - iptables("-X") - iptables("-t nat -X") - print OK - - def test_mac_ip(self) : - """ Reconstruit la correspondance MAC-IP des machines des adhérents """ - self.anim = anim(' Chaîne TEST_MAC-IP',len(self.__machines())+1) - iptables("-t nat -P PREROUTING ACCEPT") - iptables("-t nat -F TEST_MAC-IP") - self.anim.cycle() - - def procedure() : - for machine in self.__machines() : - self.__test_mac_ip(machine) - self.anim.cycle() - iptables("-t nat -P PREROUTING DROP") - self.anim.reinit() - print OK - - self.exception_catcher(procedure) - - def serv_out_adm(self) : - self.anim = anim(' Output vers VLAN adm', len(self.adm_users)) - for user in self.adm_users : - self.anim.cycle() - try: - iptables("-t nat -A SERV_OUT_ADM -m owner --uid-owner %d -j ACCEPT" % pwd.getpwnam(user)[2]) - except KeyError: - continue - except: - print "Erreur inattendue: ", sys.exc_info()[0] - - iptables("-t nat -A SERV_OUT_ADM -p tcp --dport ldap -j ACCEPT") - iptables("-t nat -A SERV_OUT_ADM -p udp --dport ldap -j ACCEPT") - iptables("-t nat -A SERV_OUT_ADM -j DROP") - self.anim.reinit() - print OK - - def __test_mac_ip(self,machine): - ip=machine.ip() - mac=machine.mac() - if machine.ipsec(): - # Machine wifi, c'est la mac de Nectaris - iptables("-t nat -A TEST_MAC-IP -s "+\ - "%s -m mac --mac-source %s -j ACCEPT"%(ip,self.mac_wifi)) - else: - # Machine fixe - iptables("-t nat -A TEST_MAC-IP -s "+\ - "%s -m mac --mac-source %s -j ACCEPT"%(ip,mac)) - - def serveur_maj(): - return - - def serveurs_maj_list_to_do(self) : - return - - def adh_maj_list_to_do(self) : - return - - def port_maj(self,ip_list) : - """ Mise à jour des ports pour les ip fournies """ - # Note : système bourrin (on efface les chaines et on refait) - # mais rapide et efficace (si qqn veut se casser le cul à - # un système aussi délicat que pour la correspondance MAC-IP...) - # -- Fred - serveur_maj = False - adh_maj = False - for ip in ip_list : - if AddrInNet(ip,self.zone_serveur) : - serveur_maj = True - else : - adh_maj = True - if serveur_maj and adh_maj : - break - to_do=[] - if serveur_maj : - self.exception_catcher(self.serveurs_maj_list_to_do) - - if adh_maj : - self.exception_catcher(self.adh_maj_list_to_do) - - # envoi d'un mail à roots - try : - from mail import mail_details - machines = [] - db = crans_ldap() - for ip in ip_list : - machines += db.search('ipHostNumber=%s' % ip)['machine'] - mail_details(machines, Subject = 'Modification du firewall de komaz concernant une machine') - #mail_details(machines, To = ['quenelle'], Subject = 'Modification du firewall du CR@NS', no_ascii = True) - except : - pass - - def mac_ip_maj(self,ip_list) : - """ Mise à jour de la correspondance MAC-IP pour les ip fournies """ - ## Que faut-il faire ? - self.anim = anim(' Analyse travail à effectuer') - if ip_list == [''] : - print OK + ' (rien à faire)' - return - - mac_ip_maj = {} - serveur_maj = False - for ip in ip_list : - machine = crans_ldap().search('ip=%s'% ip)['machine'] - if not machine : - # Destruction des occurences - if AddrInNet(ip,self.zone_serveur) : - serveur_maj = True - else : - mac_ip_maj[ip] = None - - elif len(machine) == 1 : - # Mise à jour de la machine - if AddrInNet(ip,self.zone_serveur) : - serveur_maj = True - else : - # Il faut avoir payé ou être une machine du crans ou un invite - if crans_ldap().search('paiement=ok&ip=%s'% ip)['machine'] or \ - machine[0].proprietaire().__class__ == crans or \ - machine[0].proprietaire().__class__ == invite : - mac_ip_maj[ip] = machine[0] - else : - mac_ip_maj[ip] = None - else : - print WARNING - if debug : - sys.stderr.write("Plusieurs machines avec l'IP %s" % ip) - - print OK - - ## Traitement - # Serveurs - if serveur_maj : - self.__serveur_maj() - - # Correspondance MAC-IP - if mac_ip_maj : - def procedure() : - warn = '' - self.anim = anim(' Actualisation TEST_MAC-IP') - for regle in iptables("-t nat -L TEST_MAC-IP -n").split('\n')[2:] : - regle = regle.split() - ip = regle[3] - mac = regle[6].lower() - if ip in mac_ip_maj.keys() : - # La règle correspond à une ip à mettre à jour - machine = mac_ip_maj[ip] - try : - if not machine : - # Il faut détruire cette entrée - iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j ACCEPT" % (ip, mac)) - else : - if ( machine.ipsec() and mac!=self.mac_wifi ) \ - or ( not machine.ipsec() and mac != machine.mac() ) : - # La correspondance MAC-IP est fausse => on ajoute la bonne règle - self.__test_mac_ip(machine) - # Supression de l'ancienne ligne - iptables("-t nat -D TEST_MAC-IP -s %s -m mac --mac-source %s -j ACCEPT" % (ip, mac)) - - # Toutes les autres occurences devront être détruites - mac_ip_maj[ip]=None - - - except IptablesError, c : - warn += c - - # Ajout des machines qui n'étaient pas dans le firewall - for machine in mac_ip_maj.values() : - if machine : - self.__test_mac_ip(machine) - if warn : - print WARNING - sys.stdout.write(warn) - else : - print OK - - self.exception_catcher(procedure) - - def build_chaine_adherent(self,chaine,methode) : - # On construit d'abord les autorisations particuli\uffffres - if not self.build_chaine(chaine, methode) : - # Puis si pas de problèmes les autorisationq par défaut - self.anim.reinit() - for proto in [ 'tcp' , 'udp' ] : - for port in self.ports_default["%s_%s" % ( proto, chaine) ] : - self.anim.cycle() - iptables("-I %s -p %s --dport %s -j ACCEPT" % (chaine, proto,port) ) - self.anim.reinit() - print OK - - def build_chaine(self,chaine, methode) : - self.anim = anim(' Chaîne %s' % chaine,len(self.__machines())+1) - iptables("-F %s" % chaine) - self.anim.cycle() - def procedure() : - for machine in self.__machines() : - methode(machine) - self.anim.cycle() - iptables("-A %s -j REJECT" % chaine) - return self.exception_catcher(procedure) - - -if __name__ == '__main__' : - print "Cette classe n'est pas utilisable telle quelle" - print " utilisée pour deriver les firewalls du Cr@ns" diff --git a/gestion/gen_confs/firewall_komaz.py b/gestion/gen_confs/firewall_komaz.py deleted file mode 100755 index 247acda8..00000000 --- a/gestion/gen_confs/firewall_komaz.py +++ /dev/null @@ -1,385 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -# The authors of this code are -# Manuel Sabban -# Frédéric Pauget -# -# Rewritten as an inherited class from firewallÃ_crans -# by Mathieu Segaud -# -# Copyright (c) 2004 Manuel Sabban, Frédéric Pauget -# Copyright (c) 2005 Mathieu Segaud -# -# Permission to use, copy, and modify this software with or without fee -# is hereby granted, provided that this entire notice is included in -# all source code copies of any software which is or includes a copy or -# modification of this software. -# -# THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR -# IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY -# REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE -# MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR -# PURPOSE. -""" Firewall de Komaz """ -import sys -sys.path.append('/usr/scripts/gestion') - -import syslog -from firewall_crans import firewall_crans, IptablesError, iptables -from lock import * -from ldap_crans import crans_ldap, ann_scol, machine, crans, invite -from affich_tools import * -from commands import getstatusoutput -from iptools import AddrInNet -syslog.openlog('firewall') - -class firewall_komaz(firewall_crans) : - """ - Structure du firewall : - table nat : - PREROUTING (policy par defaut : DROP) - 1) passage par TEST_VIRUS_FLOOD pour tout ce qui n'est pas dans zone_serveur - 2) passage dans RESEAUX_NON_ROUTABLES_DST - 3) passage est paquets venant de l'extérieur dans RESEAUX_NON_ROUTABLES_SRC - 4) on laisse passer vers filter les paquets suivants : - source ou destination les serveurs de serveurs_crans - ce qui vient de l'extérieur - 5) passage par TEST_MAC-IP - - TEST_VIRUS_FLOOD droppe les paquets contenant des virus ou les paquets de flood - RESEAUX_NON_ROUTABLES_DST droppe les paquets dont la destination est non routable - RESEAUX_NON_ROUTABLES_SRC droppe les paquets dont la source est non routable - TEST_MAC-IP envoi les bon paquets vers CRANS_VERS_EXT - - table filter : - FORWARD (policy par defaut : ACCEPT) - 1) passage par BLACKLIST - 2) passage pas FILTRE_P2P (REJECT sur tout le trafic p2p) - 3) ce qui a pour source les serveurs de serveurs_crans est dirigé vers SERVEURS_VERS_EXT - 4) ce qui a pour destination les serveurs de serveurs_crans est dirigé EXT_VERS_SERVEURS - 5) tout ce qui vient de l'interface externe est dirigé vers EXT_VERS_CRANS - 6) ce qui a pour source les serveurs de serveurs_crans est dirigé vers EXT_VERS_CRANS - - BLACKLIST fitre des ip blacklistées (reject) - FILTRE_P2P filtre le traffic de p2p - EXT_VERS_CRANS et CRANS_VERS_EXT - ACCEPT pour les paquets vers les machines du crans (test port-ip) - REJECT pour le reste - EXT_VERS_SERVEURS et SERVEURS_VERS_EXT - ACCEPT pour bon mac-ip-port - REJECT pour le reste - """ - - # interfaces physiques - eth_ext = "eth2" - eth_int = "eth0" - - # Ports ouverts - ports_default = { 'tcp_EXT_VERS_CRANS' : [ '22' ], - 'tcp_CRANS_VERS_EXT': [ ':79', '81:134', '136', '140:444', '446:'], - 'udp_EXT_VERS_CRANS' : [ ], - 'udp_CRANS_VERS_EXT': [ ':136','140:'] } - - - ports_virus = { 'tcp' : [ 135, 445 ] , 'udp' : [] } - - # Filtrage du peer to peer - filtres_p2p = [ ('bit', 'Bittorrent'), - ('apple', 'AppleJuice'), - ('soul', 'SoulSeek'), - ('winmx', 'WinMX'), - ('edk', 'eDonkey'), - ('dc', 'DirectConnect'), - ('kazaa', 'KaZaa'), - ('ares', 'Ares'), - ('gnu', 'GNUtella') ] - ports_p2p = [ '412', '1214', '4662:4665' , '6346:6347', '6699', '6881:6889' ] - - debug = 1 - - def nat_table_tweaks(self) : - self.anim = anim(' règles spécifiques à komaz') - for chaine in [ 'LOG_VIRUS', 'LOG_FLOOD', 'TEST_VIRUS_FLOOD' ] : - iptables('-t nat -N %s' % chaine) - - iptables("-t nat -I PREROUTING 3 -s ! %s -j TEST_VIRUS_FLOOD" % self.zone_serveur) - iptables("-t nat -I PREROUTING 6 -i %s -j ACCEPT" % self.eth_ext ) - iptables("-t nat -I PREROUTING 6 -s %s -j ACCEPT" % self.zone_serveur ) - iptables("-t nat -I PREROUTING 6 -d %s -j ACCEPT" % self.zone_serveur ) - iptables("-t nat -R PREROUTING 5 -i %s -j RESEAUX_NON_ROUTABLES_SRC" % self.eth_ext ) - print OK - - def filter_table_tweaks(self) : - self.anim = anim(' règles spécifiques à komaz') - for chaine in [ 'ADMIN_VLAN', 'EXT_VERS_SERVEURS', 'SERVEURS_VERS_EXT' , 'EXT_VERS_CRANS', 'CRANS_VERS_EXT', 'BLACKLIST_SRC', 'BLACKLIST_DST' , 'FILTRE_P2P' ] : - iptables('-N %s' % chaine) - iptables("-A FORWARD -i lo -j ACCEPT") - iptables("-A FORWARD -p icmp -j ACCEPT") - iptables("-A FORWARD -i %s -d %s -j REJECT" % (self.eth_ext, self.vlan_adm) ) - iptables("-A FORWARD -i %s -j BLACKLIST_DST" % self.eth_ext ) - iptables("-A FORWARD -o %s -j BLACKLIST_SRC" % self.eth_ext ) - iptables("-A FORWARD -s ! %s -d ! %s -j FILTRE_P2P" % (self.zone_serveur, self.zone_serveur) ) - iptables("-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT") - iptables("-A FORWARD -i %s -d %s -j ADMIN_VLAN" % (self.eth_int, self.vlan_adm) ) - iptables("-A FORWARD -i %s -d %s -j EXT_VERS_SERVEURS" % (self.eth_ext, self.zone_serveur) ) - iptables("-A FORWARD -o %s -s %s -j SERVEURS_VERS_EXT" % (self.eth_ext, self.zone_serveur) ) - iptables("-A FORWARD -i %s -j EXT_VERS_CRANS" % self.eth_ext ) - iptables("-A FORWARD -o %s -j CRANS_VERS_EXT" % self.eth_ext ) - print OK - - def enable_route(self) : - self.anim = anim(" Mise en place routage") - warn = '' - for cmd in [ 'echo 1 > /proc/sys/net/ipv4/ip_forward' , - 'echo 65536 > /proc/sys/net/ipv4/ip_conntrack_max' , - 'modprobe ip_conntrack_ftp' , - 'modprobe ip_conntrack_h323', - 'modprobe ip_conntrack_irc' ] : - status,output=getstatusoutput(cmd) - if status : - warn += output + '\n' - if warn : - print WARNING - if self.debug : - print warn - else : - print OK - - def disable_route(self) : - self.anim = anim(" Arret routage") - status,output=getstatusoutput('echo 0 > /proc/sys/net/ipv4/ip_forward') - if status : - print ERREUR - else : - print OK - - def start_fw_funcs(self) : - self.exception_catcher(self.log_chaines) - self.exception_catcher(self.test_virus_flood) - self.exception_catcher(self.reseaux_non_routables) - self.exception_catcher(self.blacklist) - self.exception_catcher(self.admin_vlan) - self.exception_catcher(self.serveurs_vers_ext) - self.exception_catcher(self.ext_vers_serveurs) - self.exception_catcher(self.crans_vers_ext) - self.exception_catcher(self.ext_vers_crans) - self.exception_catcher(self.test_mac_ip) - self.exception_catcher(self.filtre_p2p) - - def serveurs_maj_list_to_do(self) : - self.exception_catcher(self.serveurs_vers_ext) - self.exception_catcher(self.ext_vers_serveurs) - - def adh_maj_list_to_do(self) : - self.exception_catcher(self.crans_vers_ext) - self.exception_catcher(self.ext_vers_crans) - - def log_chaines(self) : - """ Construction des chaines de log (LOG_VIRUS et LOG_FLOOD) """ - self.anim = anim(' Création des chaines de log') - for filtre in [ 'VIRUS', 'FLOOD' ] : - # Vidage de la chaine - iptables('-t nat -F LOG_%s' % filtre) - - iptables('-t nat -A LOG_%s %s %s:' % (filtre, self.log_template, filtre.capitalize()) ) - iptables('-t nat -A LOG_%s -j DROP' % filtre ) - self.anim.cycle() - self.anim.reinit() - print OK - - def test_virus_flood(self) : - """ Construction de la chaîne TEST_VIRUS """ - iptables('-t nat -F TEST_VIRUS_FLOOD') - self.anim = anim(' Filtrage virus et floods') - - for proto, ports in self.ports_virus.items() : - for port in ports : - iptables('-t nat -A TEST_VIRUS_FLOOD -p %s --dport %s -j LOG_VIRUS' % (proto, port) ) - self.anim.cycle() - - iptables('-t nat -A TEST_VIRUS_FLOOD %s -j RETURN' % self.filtre_flood) # Les limites en négatif ca ne marche pas. - self.anim.cycle() - iptables('-t nat -A TEST_VIRUS_FLOOD -j LOG_FLOOD') - self.anim.reinit() - print OK - - def serveurs_vers_ext(self) : - """ Reconstruit la chaine SERVEURS_VERS_EXT """ - if not self.build_chaine('SERVEURS_VERS_EXT', self.__serveurs_vers_ext) : - self.anim.reinit() - print OK - - def ext_vers_serveurs(self) : - """ Reconstruit la chaine EXT_VERS_SERVEURS """ - if not self.build_chaine('EXT_VERS_SERVEURS', self.__ext_vers_serveurs) : - self.anim.reinit() - print OK - - def crans_vers_ext(self) : - """ Reconstruit la chaine CRANS_VERS_EXT """ - self.build_chaine_adherent('CRANS_VERS_EXT',self.__crans_vers_ext) - - def ext_vers_crans(self) : - """ Reconstruit la chaine EXT_VERS_CRANS """ - self.build_chaine_adherent('EXT_VERS_CRANS',self.__ext_vers_crans) - - def admin_vlan(self) : - """ Reconstruit la chaine ADMIN_VLAN """ - iptables("-F ADMIN_VLAN") - nounou_machines = [] - for adherent in crans_ldap().search('droits=Nounou')['adherent'] : - for machine in adherent.machines() : - nounou_machines.append(machine.ip()) - - iptables("-A ADMIN_VLAN -j REJECT") - self.anim = anim(' Chaîne ADMIN_VLAN', len(nounou_machines)) - for machine in nounou_machines : - self.anim.cycle() - iptables("-I ADMIN_VLAN -p tcp -s %s --dport ssh -j ACCEPT" % machine) - self.anim.reinit() - print OK - - def __serveurs_vers_ext(self,machine): - ip=machine.ip() - if not AddrInNet(ip,self.zone_serveur): - # C'est une machine adhérent, rien à faire ici - return - - mac = machine.mac() - ports = { 'tcp' : machine.portTCPout(), - 'udp' : machine.portUDPout() } - - for proto in [ 'tcp', 'udp' ] : - for port in ports[proto].split() : - iptables("-I SERVEURS_VERS_EXT -s %s -p %s --dport %s -m mac --mac-source %s -j ACCEPT" \ - %(ip,proto,port,mac)) - - def __ext_vers_serveurs(self,machine): - ip=machine.ip() - if not AddrInNet(ip,self.zone_serveur): - # C'est une machine adhérent, rien à faire ici - return - - ports = { 'tcp' : machine.portTCPin(), - 'udp' : machine.portUDPin() } - - for proto in [ 'tcp', 'udp' ] : - for port in ports[proto].split() : - iptables("-I EXT_VERS_SERVEURS -d %s -p %s --dport %s -j ACCEPT"\ - %(ip,proto,port)) - - def __crans_vers_ext(self,machine): - ip=machine.ip() - if AddrInNet(ip,self.zone_serveur): - # C'est un serveur, rien à faire ici - return - - ports = { 'tcp' : machine.portTCPout(), - 'udp' : machine.portUDPout() } - - for proto in [ 'tcp', 'udp' ] : - for port in ports[proto].split() : - iptables("-I CRANS_VERS_EXT -s %s -p %s --dport %s -j ACCEPT" \ - %(ip,proto,port)) - - def __ext_vers_crans(self,machine): - ip=machine.ip() - if AddrInNet(ip,self.zone_serveur): - # C'est un serveur, rien à faire ici - return - - ports = { 'tcp' : machine.portTCPin(), - 'udp' : machine.portUDPin() } - - for proto in [ 'tcp', 'udp' ] : - for port in ports[proto].split() : - iptables("-I EXT_VERS_CRANS -d %s -p %s --dport %s -j ACCEPT" \ - %(ip,proto,port)) - - def blacklist(self): - """ Construit les chaines de blackliste (BLACKLIST_{DST,SRC}) """ - self.anim = anim(" Blackliste") - iptables('-F BLACKLIST_DST') - iptables('-F BLACKLIST_SRC') - - blacklist=[] - search = crans_ldap().search('blacklist=*&paiement=%s'% ann_scol) - for entite in search['adherent']+search['club']+search['machine']: - self.anim.cycle() - sanctions = entite.blacklist_actif() - if 'upload' in sanctions or 'warez' in sanctions : - from ldap_crans import machine - if entite.__class__ == machine: - blacklist+=[entite] - else: - blacklist+=entite.machines() - - for machine in blacklist: - iptables("-A BLACKLIST_DST -d %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip()) - iptables("-A BLACKLIST_SRC -s %s -j REJECT --reject-with icmp-host-prohibited" % machine.ip()) - - self.anim.reinit() - print OK - - def filtre_p2p(self): - """ Construit la chaines de filtrage du p2p (FILTRE_P2P) """ - self.anim = anim(" Filtrage p2p") - iptables('-F FILTRE_P2P') - - # On ne filtre que ce qui passe sur l'interface externe - iptables('-A FILTRE_P2P -i %s -o %s -j RETURN' % (self.eth_int, self.eth_int) ) - - for port in self.ports_p2p : - iptables('-A FILTRE_P2P -p tcp --dport %s -j REJECT --reject-with icmp-admin-prohibited' % port ) - iptables('-A FILTRE_P2P -p udp --dport %s -j REJECT --reject-with icmp-admin-prohibited' % port ) - self.anim.cycle() - - for filtre in self.filtres_p2p : - iptables('-A FILTRE_P2P -m ipp2p --%s -j LOG --log-prefix "IPP2P=%s "' % (filtre[0], - filtre[1])) - iptables('-A FILTRE_P2P -m ipp2p --%s -j REJECT --reject-with icmp-admin-prohibited' % filtre[0]) - self.anim.cycle() - - self.anim.reinit() - print OK - - def serveurs_maj(self) : - self.exception_catcher(self.serveurs_vers_ext) - - - - -if __name__ == '__main__' : - # Chaines pouvant être recontruites - global chaines - chaines = [ 'log_chaines' , 'test_virus_flood', 'reseaux_non_routables', - 'test_mac_ip' , 'blacklist' , 'ext_vers_serveurs' , 'serveurs_vers_ext', - 'ext_vers_crans', 'crans_vers_ext' , 'filtre_p2p', 'admin_vlan' ] - - def __usage(txt=None) : - if txt!=None : cprint(txt,'gras') - - print """Usage: - %(p)s start : Construction du firewall. - %(p)s restart : Reconstruction du firewall. - %(p)s stop : Arrêt du firewall. - %(p)s chaine : reconstruit les chaines -Les chaines pouvant être reconstruites sont : - %(chaines)s -Pour reconfiguration d'IPs particulières, utiliser generate. """ % \ -{ 'p' : sys.argv[0].split('/')[-1] , 'chaines' : '\n '.join(chaines) } - sys.exit(-1) - - # Bons arguments ? - if len(sys.argv) == 1 : - __usage() - for arg in sys.argv[1:] : - if arg in [ 'stop', 'restart', 'start' ] and len(sys.argv) != 2 : - __usage("L'argument %s ne peut être employé que seul." % arg) - - if arg not in [ 'stop', 'restart', 'start' ] + chaines : - __usage("L'argument %s est inconnu." % arg) - - fw = firewall_komaz() - for arg in sys.argv[1:] : - eval('fw.%s()' % arg) diff --git a/gestion/gen_confs/generate.py b/gestion/gen_confs/generate.py index 80110cd1..a81cabb6 100755 --- a/gestion/gen_confs/generate.py +++ b/gestion/gen_confs/generate.py @@ -1,5 +1,5 @@ #! /usr/bin/env python -# -*- coding: iso-8859-15 -*- +# -*- coding: utf-8 -*- # Copyright (C) Frédéric Pauget # Licence : GPLv2 @@ -13,25 +13,16 @@ Les options avec = doivent arguments peuvent être founis pour une même option, les séparer par & """ -import sys, signal, os, commands, getopt, smtplib, shutil +import sys, signal, os, getopt sys.path.append('/usr/scripts/gestion') -from ldap_crans import crans_ldap, crans, smtpserv, hostname, invite +from ldap_crans import crans_ldap, crans, hostname, invite from lock import * -from affich_tools import anim, cprint, OK, ERREUR, WARNING +from affich_tools import anim, cprint, OK from time import localtime, strftime, time, sleep import config - -args_autorises = ['quiet', 'remove=', 'add=', 'list' ,'help', 'reconnect'] -if hostname == 'zamok' : - args_autorises += [ 'home=', 'mail_bienvenue=', 'ML-ENS=', 'droits', 'switch=' , 'dhcp', 'dns', 'firewall' , 'del_user=', 'blacklist_upload', 'autostatus'] -elif hostname == 'nectaris' : - args_autorises += [ 'conf_wifi', 'bornes_wifi=' , 'droits-nectaris', 'dhcp-nectaris'] -elif hostname == 'sila' : - args_autorises += [ 'bl_squid_upload', 'blacklist_virus' , 'blacklist_warez' , 'bl_chbre_invalide', 'bl_carte_etudiant' ] -elif hostname == 'komaz' : - args_autorises += [ 'firewall-komaz=' , 'firewall-komaz-ports=' , 'firewall-komaz-blacklist'] +from inspect import getargspec # On vérifie que l'on est root if os.getuid() != 0: @@ -43,466 +34,309 @@ signal.signal(signal.SIGINT,signal.SIG_IGN) # Pas de Ctrl-C db = crans_ldap() make_lock('auto_generate','Big lock',nowait=1) -##### Options fournies ? -try : - if len(sys.argv) > 1 : - options, arg = getopt.getopt(sys.argv[1:], 'h', args_autorises) - else : - options, arg = ( [],'') -except getopt.error, msg : - sys.stderr.write('%s\n' % msg) - sys.exit(255) - -debug = 1 # défaut -to_do = {} - -for opt, val in options : - if opt == '--quiet' : - debug = 0 - - elif opt == '--remove' : - for serv in val.split('&') : - print 'Supression de %s' % serv - db.services_to_restart('-%s' % serv) - sys.exit(0) - - elif opt == '--list' : - print 'Services à redémarrer :' - print db.services_to_restart() - sys.exit(0) - - elif opt == '--reconnect' : - # Personnes à reconnecter - print 'Recheche personnes en fin de sanction.' - hier = strftime('%d/%m/%Y %H:%M'.split()[0],localtime(time()-60*60*24)) - c = db.search('blacklist=*,%s*' % hier) - services = [] - for a_reco in c['adherent'] + c['machine'] + c['club'] : - for bl in a_reco.blacklist() : - fin, sanction = bl.split(',')[1:3] - if fin.split()[0] == hier and sanction not in services : - services.append(sanction) - for s in services : - print "Ajout de blacklist_%s pour reconfiguration" % s - db.services_to_restart('blacklist_%s' % s.encode()) - sys.exit(0) - - elif opt=='--add' : - # Ajout d'un item dans les services à redémarrer - for serv in val.split('&') : - if serv.find(',')!=-1 : - serv, arg = serv.split(',',1) - arg = arg.split(',') - else : - arg = [] - - print 'Ajout de %s (%s)' % ( serv, arg ) - db.services_to_restart(serv, arg) - sys.exit(0) - - elif opt =='-h' or opt == '--help' : - print __doc__ % { 'prog' : sys.argv[0].split('/')[-1] , 'options' : '\n\t'.join(args_autorises) } - sys.exit(0) - - elif len(opt)>2 and opt[:2]=='--' : - to_do[opt[2:]] = val.split('&') +class base_reconfigure : + __machines = () + __service_develop = { + 'macip' : [ 'rouge-macip', 'bleu-macip', 'sila-macip' , 'komaz-macip', 'zamok-macip' ] , + 'droits': [ 'zamok-droits', 'nectaris-droits' ] , + 'blacklist_upload' : [ 'bl_squid_upload' , 'komaz-blacklist'] } -##### Lecture de la base LDAP si besion ce qu'il y a a faire et préparation -if not to_do : - if debug : print 'Lecture services à redémarrer dans la base LDAP' - to_do = db.services_to_restart() - auto = 1 -else : - auto = 0 - if debug : print 'Services à redémarrer imposés (non lecture de la base LDAP)' + def __init__(self,to_do=[]) : + if not to_do : + if debug : print 'Lecture services à redémarrer dans la base LDAP' + to_do = db.services_to_restart() + auto = 1 + # Développements nécessaires + for service,args in to_do.items() : + # Services spéciaux portant sur plusieurs machines + to_add = self.__service_develop.get(service,[]) + if to_add : + for s in to_add : + db.services_to_restart(s,args) + db.services_to_restart('-' + service) + else : + auto = 0 + if debug : print 'Services à redémarrer imposés (non lecture de la base LDAP)' -inst = [] - -if hostname == 'zamok': - if 'del_user' in to_do.keys() : - if auto : db.services_to_restart('-del_user') - cprint('Archivage fichiers utilisateur','gras') - for args in to_do['del_user'] : - anim('\t' + args) - try : - login, home = args.split(',') - if not login or not home : - raise ValueError('Argument invalide') - warn = '' - f = config.cimetiere + '/files/' + strftime('%Y-%m-%d-%Hh%Mm_') + login + '.tar.bz2' - status, output = commands.getstatusoutput("tar cjf '%s' '%s' /var/spool/mail/%s" % ( f,home,login) ) - if ( status != 512 and status!=0 ) or not os.path.isfile(f) : - # La 512 est si un des paths n'exite pas. - raise OSError(output) - if os.path.isdir(home) and os.stat(home)[4] >= 500 : - shutil.rmtree(home) - else : - warn += '%s incorrect\n' % home - if os.path.isfile('/var/spool/mail/' + login ) : - os.unlink('/var/spool/mail/' + login) - else : - warn += '/var/spool/mail/%s incorrect\n' % login - - if warn : - print WARNING - if debug : - sys.stderr.write(warn) - else : - print OK - except : - print ERREUR - # On devra le refaire la prochaine fois - if auto : db.services_to_restart('del_user',[args]) - if debug : + for serv,args in to_do.items() : + # Au cas ou le service porte sur plusieurs machines + service = serv.replace('%s-'%hostname,'') + if hasattr(self,service) : + # Le service est à reconfigurer sur cette machine + db.services_to_restart('-%s' % serv) + try: + m = getattr(self,service) + if len(getargspec(m)[0])>1 : + m(args) + else : + m() + except: + if auto : db.services_to_restart(serv,args) + sys.stderr.write('%s :'%serv) import traceback traceback.print_exc() - - if 'home' in to_do.keys() : - if auto : db.services_to_restart('-home') - cprint('Création home','gras') - for args in to_do['home'] : - anim('\t' + args) - try : - home, uid, login = args.split(',') - ### Home - if not os.path.exists(home) : - # Le home n'existe pas - os.mkdir(home, 0755) - os.chown(home, int(uid) ,config.gid) - elif os.path.isdir(home) : - # Il y un répertoire existant - # Bon UID ? - stat = os.stat(home) - if stat[4] != int(uid) or stat[5] != config.gid : - # Le home n'est pas à la bonne personne - raise OSError('home existant') - - ### Mail - try : - os.mkdir(home + '/Mail', 0700) - os.chown(home + '/Mail', int(uid) ,config.gid) - except : - # Pas grave - pass - - ### Quota - status, output = commands.getstatusoutput('/usr/sbin/edquota -p pauget %s' % login ) - if status : - print WARNING - if debug : - sys.stderr.write(output+'\n') - else : - print OK - except : - print ERREUR - # On devra le refaire la prochaine fois - if auto : db.services_to_restart('home',[args]) - if debug : - import traceback - traceback.print_exc() - - if 'mail_bienvenue' in to_do.keys() : - if auto : db.services_to_restart('-mail_bienvenue') - cprint('Envoi mail de bienvenue','gras') - for mail in to_do['mail_bienvenue'] : - anim('\t' + mail) - try : - From = "respbats@crans.org" - To = mail - if To.find('@') == -1 : To += '@crans.org' - conn=smtplib.SMTP(smtpserv) - conn.sendmail(From, To , config.txt_mail_bienvenue % { 'From' : From, 'To' : To }) - conn.quit() - print OK - except Exception, c: - print ERREUR - if auto : db.services_to_restart('mail_bienvenue',[mail]) - if debug : - import traceback - traceback.print_exc() - - if 'ML-ENS' in to_do.keys() : - if auto : db.services_to_restart('-ML-ENS') - cprint('Inscription ML-ENS','gras') - for mail in to_do['ML-ENS'] : - anim('\t'+mail) - status, output = commands.getstatusoutput("echo '%s' | /usr/sbin/add_members -r - com-ens >/dev/null 2>&1" % mail) - if status : - # Il y a eu une erreur - print ERREUR - if auto : db.services_to_restart('ML-ENS', [mail]) - if debug : - sys.stderr.write(output+'\n') + + if debug : + reste = db.services_to_restart() + if reste : + print "Reste à faire :" + for item in reste.items() : + print '\t%s(%s)' % item else : - print OK - - if 'droits' in to_do.keys() : - if auto : db.services_to_restart('-droits') - db.services_to_restart('droits-nectaris') - try: - from gen_confs.droits import droits - a = droits() - a.uids = to_do['droits'] - a.debug = debug - a.reconfigure() - except: - if auto : db.services_to_restart('droits',to_do['droits']) + print "Plus rien à faire" - if 'blacklist_upload' in to_do.keys() : - if auto : db.services_to_restart('-blacklist_upload') - db.services_to_restart('bl_squid_upload') - db.services_to_restart('firewall-komaz-blacklist') - try: - from gen_confs.firewall import bl_upload_fw - a = bl_upload_fw() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('blacklist_upload') - - if 'switch' in to_do.keys() : - if auto : db.services_to_restart('-switch') - try: - from gen_confs.switchs import switch - a = switch(to_do['switch']) - a.debug = debug - a.reconfigure() - except: - if auto : db.services_to_restart('switch',to_do['switch']) - sys.stdout.write('Erreur dans la config des switchs.\n') - if debug : - import traceback - traceback.print_exc() - - if 'mail_modification_machine' in to_do.keys() : - - cprint('Modification d\'une machine : envoi d\'un mail à roots@crans.org','gras') - - try : - from mail import mail_details - - # liste des machines - machines = [] - for ip in to_do['mail_modification_machine'] : - anim('\t' + ip) - print OK - machines += db.search('ipHostNumber=%s' % ip)['machine'] - - # envoi du mail - mail_details(machines, Subject = 'Modification d\'une machine de l\'association') - - if auto : db.services_to_restart('-mail_modification_machine') + def _machines(self) : + """ Retourne les machines de la base étant 'à jour' """ + if not self.__machines : + # Récolte des données + cprint('Lecture base LDAP','gras') + # Machines de l'assoce + self.__machines = crans(db.conn).machines() + # Machines des invités + self.__machines += invite(db.conn).machines() + # Machines des adhérents et clubs de l'année en cours + base = db.search('paiement=ok') + base = base['adherent'] + base['club'] + a = anim('\ttri machines',len(base)) + for adh in base : + a.cycle() + # Adhérent ayant payé l'année en cours + if 'bloq' in adh.blacklist_actif() : + # Adhérent ignoré + continue + self.__machines += adh.machines() + a.reinit() print OK + + return self.__machines - except : - print ERREUR + def _do(self,service,machines=None) : + # Reconfiguration des services + service.debug = debug + if machines : + service.machines = machines + service.reconfigure() - if 'autostatus' in to_do.keys() : - if auto : db.services_to_restart('-autostatus') - try: - from autostatus import autostatus - a = autostatus() - a.debug = debug - a.reconfigure() - except: - if auto : db.services_to_restart('autostatus') + def macip(self,ips) : + import firewall + cprint("Mise à jour correspondance MAC-IP",'gras') + eval("firewall.firewall_%s()" % hostname).mac_ip_maj(ips) + +class rouge(base_reconfigure) : + def switch(self,chambres) : + from gen_confs.switchs import switch + self._do(switch(chambres)) - # Les services suivants ont besoin de la liste des machines - # On va donc la lire une seule fois pour leur passer ensuite + def mail_modif(self,trucs) : + """ trucs est une liste de recherches à effectuer dans la base + l'affichage des résultats formera le corps du mail """ + from supervison import mail + self._do(mail(trucs)) - restartlater = [] - if 'dns' in to_do.keys() : - from gen_confs.bind import dns - inst.append([dns(),"dns"]) + def mail_bienvenue(self,mails) : + from adherents import mail_bienvenue + self._do(mail_bienvenue(mails)) - if 'dhcp' in to_do.keys() : - from gen_confs.dhcpd import dhcp - inst.append([dhcp(),"dhcp"]) +class bleu(base_reconfigure) : + # Tout est dans le parent + pass - if 'firewall' in to_do.keys() : - # Quand sila et komaz liront la base LDAP - from gen_confs.firewall import firewall - inst.append([firewall(),"firewall"]) +class vert(base_reconfigure) : + def home(self,args) : + from adherents import home + self._do(home(args)) + def del_user(self,args) : + from adherents import del_user + self._do(del_user(args)) -elif hostname == 'nectaris': - restart_wifi_update = False - if 'conf_wifi' in to_do.keys() or 'bornes_wifi' in to_do.keys(): +class komaz(base_reconfigure) : + def __fw(self) : + if not hasattr(self,'__real_fw') : + from firewall_komaz import firewall_komaz + self.__real_fw = firewall_komaz() + return self.__real_fw + + def macip(self,ips) : + cprint("Mise à jour correspondance MAC-IP",'gras') + self.__fw().mac_ip_maj(ips) + + def ports(self,ips) : + self.__fw().port_maj(ips) + + def blacklist(self) : + self.__fw().blacklist() + +class sila(base_reconfigure) : + def bl_carte_etudiant(self) : + from gen_confs.squid import squid_carte + self._do(squid_carte()) + + def blacklist_virus(self) : + from gen_confs.squid import squid_virus + self._do(squid_virus()) + + def blacklist_warez(self) : + from gen_confs.squid import squid_warez + self._do(squid_warez()) + + def bl_squid_upload(self) : + from gen_confs.squid import squid_upload + self._do(squid_upload()) + + def bl_chbre_invalide(self) : + from gen_confs.squid import squid_chbre + self._do(squid_chbre()) + +class nectaris(base_reconfigure) : + __restart_wifi_update = False + + def macip(self) : + # Surcharge car rien à faire ici + pass + + def __wifi(self) : # On arrete wifi-update os.system("kill $(cat /var/run/wifi-update.pid)") sleep(1) - restart_wifi_update = True - - # On s'occupe de nectaris - if 'conf_wifi' in to_do.keys(): - if auto : db.services_to_restart('-conf_wifi') - try: - from gen_confs.wifi import conf_wifi - a = conf_wifi() - a.debug = debug - a.reconfigure() - # On va aussi demander la reconfiguration de toutes les bornes - to_do['bornes_wifi'] = [] - except: - if auto : db.services_to_restart('conf_wifi') - sys.stdout.write('Erreur dans la config du wifi.\n') - - if 'dhcp-nectaris' in to_do.keys() : - from gen_confs.dhcpd import dhcp - inst.append([dhcp(),"dhcp-nectaris"]) - - if 'bornes_wifi' in to_do.keys(): - if auto : db.services_to_restart('-bornes_wifi') - try: - from gen_confs.wifi import bornes_wifi - if to_do['bornes_wifi']==['all']: - a = bornes_wifi() - else: - a = bornes_wifi(to_do['bornes_wifi']) - a.debug = debug - a.reconfigure() - except: - # Pas terrible : on va redemarrer les bornes qui ont redemarré correctement - if auto : db.services_to_restart('bornes_wifi', to_do['bornes_wifi']) - sys.stdout.write('Erreur dans la config des bornes wifi.\n') - - if 'droits-nectaris' in to_do.keys(): - if auto : db.services_to_restart('-droits-nectaris') - try: - from gen_confs.droits import droits - a = droits() - a.debug = debug - a.reconfigure() - except: - if auto : db.services_to_restart('droits-nectaris') - sys.stdout.write('Erreur dans la config des droits sur nectaris.\n') - - if restart_wifi_update: - os.system("cd / ; systrace -d /etc/systrace/wifi-update -A /usr/local/bin/twistd --syslog -o -y /usr/scripts/gestion/wifi-update.py --pidfile=/var/run/wifi-update.pid") - -elif hostname == 'sila' : - if 'bl_carte_etudiant' in to_do.keys() : - if auto : db.services_to_restart('-bl_carte_etudiant') - try: - from gen_confs.squid import squid_carte - a = squid_carte() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('bl_carte_etudiant') - - if 'blacklist_virus' in to_do.keys() : - if auto : db.services_to_restart('-blacklist_virus') - try: - from gen_confs.squid import squid_virus - a = squid_virus() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('blacklist_virus') - - if 'blacklist_warez' in to_do.keys() : - if auto : db.services_to_restart('-blacklist_warez') - try: - from gen_confs.squid import squid_warez - a = squid_warez() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('blacklist_warez') - - if 'bl_squid_upload' in to_do.keys() : - if auto : db.services_to_restart('-bl_squid_upload') - try: - from gen_confs.squid import squid_upload - a = squid_upload() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('bl_squid_upload') - - if 'bl_chbre_invalide' in to_do.keys() : - if auto : db.services_to_restart('-bl_chbre_invalide') - try: - from gen_confs.squid import squid_chbre - a = squid_chbre() - a.debug = debug - a.reconfigure() - except: - if auto: db.services_to_restart('bl_chbre_invalide') - -elif hostname == 'komaz' : - if 'firewall-komaz' in to_do.keys() or \ - 'firewall-komaz-ports' in to_do.keys() or \ - 'firewall-komaz-blacklist' in to_do.keys() : - from firewall_komaz import firewall_komaz - fw = firewall_komaz() - fw.debug = debug + self.__restart_wifi_update = True - cprint('Reconfiguration firewall','gras') - if 'firewall-komaz' in to_do.keys() : - if auto : db.services_to_restart('-firewall-komaz') - try : - fw.mac_ip_maj(to_do['firewall-komaz']) - except : - if auto : db.services_to_restart('firewall-komaz',to_do['firewall-komaz']) + def conf_wifi(self) : + from gen_confs.wifi import conf_wifi, bornes_wifi + self.__wifi() + self._do(conf_wifi()) + # On va aussi reconfigurer toutes les bornes + self._do(bornes_wifi()) - if 'firewall-komaz-ports' in to_do.keys() : - if auto : db.services_to_restart('-firewall-komaz-ports') - try : - fw.port_maj(to_do['firewall-komaz-ports']) - except : - if auto : db.services_to_restart('firewall-komaz-ports',to_do['firewall-komaz-ports']) - - if 'firewall-komaz-blacklist' in to_do.keys() : - if auto : db.services_to_restart('-firewall-komaz-blacklist') - try : - fw.blacklist() - except : - if auto : db.services_to_restart('firewall-komaz-blacklist',to_do['firewall-komaz-blacklist']) - -# On indique que les services seront a priori redemarrés -if auto : - for i in inst: - db.services_to_restart("-%s" % i[1]) -## On fait ce qu'il reste à faire + def bornes_wifi(self,bornes) : + from gen_confs.wifi import bornes_wifi + self.__wifi() + self._do(bornes_wifi(bornes)) -if inst : - # Récolte des données - cprint('Lecture base LDAP','gras') - # Machines de l'assoce - machines = crans(db.conn).machines() - # Machines des invités - machines += invite(db.conn).machines() - # Machines des adhérents et clubs de l'année en cours - base = db.search('paiement=ok') - base = base['adherent'] + base['club'] - a = anim('\ttri machines',len(base)) - for adh in base : - a.cycle() - # Adhérent ayant payé l'année en cours - if 'bloq' in adh.blacklist_actif() : - # Adhérent ignoré - continue - machines += adh.machines() - a.reinit() - print OK - - # Reconfiguration des services - - for i in inst : - i[0].debug = debug - i[0].machines = machines - try : - i[0].reconfigure() - except : - # Erreur, il faudra relancer le service la prochaine fois - if auto : db.services_to_restart('%s' % i[1]) - sys.stdout.write('Erreur dans la config de %s.\n' % i[1]) + def dhcp(self) : + from gen_confs.dhcpd import dhcp + self._do(dhcp(),self._machines()) -if debug : - print 'Non traité ici mais signalé dans la base LDAP : \n\t', db.services_to_restart() + def droits(self) : + from gen_confs.droits import droits_openbsd + self._do(droits_openbsd()) + + def __del__(self) : + if self.__restart_wifi_update : + os.system("cd / ; systrace -d /etc/systrace/wifi-update -A /usr/local/bin/twistd --syslog -o -y /usr/scripts/gestion/wifi-update.py --pidfile=/var/run/wifi-update.pid") + +class zamok(base_reconfigure) : + def home(self,args) : + from adherents import home + self._do(home(args)) + + def del_user(self,args) : + from adherents import del_user + self._do(del_user(args)) + + def ML_ens(self,mails) : + from adherents import ML_ens + self._do(ML_ens(mails)) + + def switch(self,chambres) : + from gen_confs.switchs import switch + self._do(switch(chambres)) + + def autostatus(self) : + from autostatus import autostatus + self._do(autostatus()) + + def droits(self) : + from gen_confs.droits import droits_ldap + self._do(droits_ldap()) + + def dns(self) : + from gen_confs.bind import dns + self._do(dns(),self._machines()) + + def dhcp(self) : + from gen_confs.dhcpd import dhcp + self._do(dhcp(),self._machines()) signal.signal(signal.SIGINT,signal.SIG_DFL) # Comportement normal de Ctrl-C - remove_lock('auto_generate') + +if __name__ == '__main__' : + classe = eval(hostname) + + args_autorises = ['quiet', 'remove=', 'add=', 'list' ,'help', 'reconnect'] + # Ajout aussi des arguments spécifiques à la machine + for nom in dir(classe) : + if nom[0]!='_' : + if len(getargspec(getattr(classe,nom))[0])>1 : + nom += '=' + args_autorises.append(nom) + + + ##### Options fournies ? + try: + if len(sys.argv) > 1 : + options, arg = getopt.getopt(sys.argv[1:], 'h', args_autorises) + else : + options, arg = ( [],'') + except getopt.error, msg : + sys.stderr.write('%s\n' % msg) + sys.exit(255) + + debug = 1 # défaut + to_do = {} + + for opt, val in options : + if opt == '--quiet' : + debug = 0 + + elif opt == '--remove' : + for serv in val.split('&') : + print 'Supression de %s' % serv + db.services_to_restart('-%s' % serv) + sys.exit(0) + + elif opt == '--list' : + print 'Services à redémarrer :' + print db.services_to_restart() + sys.exit(0) + + elif opt == '--reconnect' : + # Personnes à reconnecter + print 'Recheche personnes en fin de sanction.' + hier = strftime('%d/%m/%Y %H:%M'.split()[0],localtime(time()-60*60*24)) + c = db.search('blacklist=*,%s*' % hier) + services = [] + for a_reco in c['adherent'] + c['machine'] + c['club'] : + for bl in a_reco.blacklist() : + fin, sanction = bl.split(',')[1:3] + if fin.split()[0] == hier and sanction not in services : + services.append(sanction) + for s in services : + print "Ajout de blacklist_%s pour reconfiguration" % s + db.services_to_restart('blacklist_%s' % s.encode()) + sys.exit(0) + + elif opt=='--add' : + # Ajout d'un item dans les services à redémarrer + for serv in val.split('&') : + if serv.find(',')!=-1 : + serv, arg = serv.split(',',1) + arg = arg.split(',') + else : + arg = [] + + print 'Ajout de %s (%s)' % ( serv, arg ) + db.services_to_restart(serv, arg) + sys.exit(0) + + elif opt =='-h' or opt == '--help' : + print __doc__ % { 'prog' : sys.argv[0].split('/')[-1] , 'options' : '\n\t'.join(args_autorises) } + sys.exit(0) + + elif len(opt)>2 and opt[:2]=='--' : + to_do[opt[2:]] = val.split('&') + + + # On fait ce qu'il y a à faire + classe(to_do) diff --git a/gestion/gen_confs/supervison.py b/gestion/gen_confs/supervison.py new file mode 100755 index 00000000..8b533fc3 --- /dev/null +++ b/gestion/gen_confs/supervison.py @@ -0,0 +1,333 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-15 -*- + +# Licence : GPLv2 + +import sys, smtplib, commands +sys.path.append('/usr/scripts/gestion') +from ldap_crans import smtpserv, crans, crans_ldap, machine, adherent, club +from whos import machine_details, adher_details, club_details +from gen_confs import gen_config +from affich_tools import cprint, OK, anim + +class mail : + """ + Envoie un mail à toutes les personnes de la liste 'To', avec les + informations détaillées des objets contenus dans 'objets' + (instances des classes adherent, machine ou club) """ + + From = 'root@crans.org' + To = [ 'roots@crans.org' ] + Subject = "Surveillance modifications de la base LDAP" + + mail_template = """From: %(From)s +To: %(To)s +Subject: %(Subject)s + +%(Text)s""" + + # Avec les caract-Aères d'échappement qui vont bien pour la couleur ?-b + couleur = False + + def __init__(self,recherches) : + self.recherches = recherches + + def reconfigure(self) : + """ Envoi le mail """ + cprint('Mail de notification de modifications','gras') + a = anim('\tRecherches dans la base',len(self.recherches)) + + db = crans_ldap() + details = [] + vus = [] + for rech in self.recherches : + for results in db.search(rech).values() : + for res in results : + if res.dn in vus : continue + vus.append(res.dn) + if res.__class__ == machine : + details.append(machine_details(res)) + elif res.__class__ == adherent : + details.append(adher_details(res)) + elif res.__class__ == club : + details.append(club_details(res)) + a.cycle() + + texte = '\n\n- - - - = = = = # # # # # # = = = = - - - -\n\n'.join(details) + + a.reinit() + if not details : + print "rien" + return + + print OK + + anim('\tEnvoi mail') + if not self.couleur : + import sre + texte = sre.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',texte) + + conn=smtplib.SMTP(smtpserv) + conn.sendmail(self.From, self.To , \ + self.mail_template % { 'From' : self.From, + 'To' : ','.join(self.To), + 'Subject' : self.Subject, + 'Text' : texte.encode('iso8859-15') } ) + conn.quit() + print OK + +class autostatus(gen_config) : + # CONFIGURATION # + ################# + + # fichier de l'autostatus + CONFFILE = '/etc/autostatus/hosts' + + # machines crans à ne pas mettre dans l'autostatus + exclude = ["non-configure.wifi.crans.org"] + + # matrice du fichier d'autostatus + matrice = """ +# Format : name address depend,list contact description + +# routeurs vers l'extérieur # +############################# + +%%HTML: Routeurs, dans l'ordre où ils sont entre le crans et l'extérieur : + +%(route)s + +# serveurs du crans # +##################### + +%%HTML:

+%%HTML: Serveurs : + +%(serveurs)s + +# ferme # +######### + +%%HTML:

+%%HTML: La ferme, diffusion de la télé : + +%(ferme)s + +# switchs # +########### + +%%HTML:

+%%HTML: Switchs : + +%(switchs)s + +# bornes wifi # +############### + +%%HTML:

+%%HTML: Bornes wifi : + +%(bornes)s + +# Sites web et Services # +######################### + +%%HTML:

+%%HTML: Sites web et Services HORS de l'ENS: +%%HTML: (21:FTP ; 80:HTTP ; 119:news ; 5190:port du protocole ICQ) + +%(exterieur)s +""" + # quelque descriptions de routeurs triés par IP (pour la route vers l'extérieur) + + infos_routeurs = {} + infos_routeurs [ '138.231.136.4' ] = ['Komaz', 'Routeur principal du CRANS'] + infos_routeurs [ '138.231.135.5' ] = ['IRTS', 'Routeur de l\'ENS assurant la liaison CRANS<->ENS'] + infos_routeurs [ '138.231.132.1' ] = ['gateway', 'Routeur de l\'ENS'] + infos_routeurs [ '138.231.176.1' ] = ['Pioneer', 'Routeur principal de l\'ENS'] + infos_routeurs [ '193.49.65.1' ] = ['RenaterCachan1' , 'Routeur Renater' ] + infos_routeurs [ '193.51.181.186' ] = ['RenaterCachan2', 'Routeur Renater'] + infos_routeurs [ '193.51.180.166' ] = ['RenaterJussieu1', 'Routeur Renater'] + infos_routeurs [ '193.51.180.158' ] = ['RenaterJussieu2', 'Routeur Renater'] + + # services extérieurs (triés par clé de dictionnaire) + # format [ nom, ip, port(0=ping), description ] + + services_exterieurs = {} + services_exterieurs ['Jussieu'] = [ 'Jussieu', '195.83.118.1', 21, 'Le serveur FTP de Jussieu. (France)', 'nobody'] + services_exterieurs ['Free'] = [ 'Free', '213.228.0.141', 21, 'Le serveur FTP de free. (France)', 'nobody' ] + services_exterieurs ['Voila'] = [ 'Voila', '195.101.94.80', 80, 'Est-ce que Voila fonctionne ? (France)', 'nobody' ] + services_exterieurs ['Yahoo!'] = [ 'Yahoo!', '66.94.230.39', 80, 'Est-ce que Yahoo! fonctionne ? (USA)', 'nobody' ] + services_exterieurs ['Altalavista'] = [ 'Altavista', '216.155.200.155', 80, 'Est-ce que Altavista fonctionne ? (USA)', 'nobody' ] + + # personnes à informer pour l'indiponibilité de certains serveurs + contact = {} + contact ['pegase.crans.org'] = 'pessoles@crans.org' + + # service à redémarer + restart_cmd = "" + + # FIN DE LA CONFIGURATION + + def __str__ (self) : + return "autostatus" + + def make_config (self, dico ) : + """ + Transforme le dico en suite lignes de configuration + """ + liste = dico.keys() + liste.sort() + append = "" + for i in liste : + append = append + " ".join( dico[i] ) + "\n" + return append.encode('iso-8859-15') + + def mail_contact (self, nom) : + # retourne le mail à qui envoyer les avis pour un serveur + if nom in self.contact.keys() : + return self.contact[nom] + else : + return 'nobody' + + def _gen (self) : + + # machines crans + ################ + + machines = crans().machines() + + # tri des machines par type + bornes = {} + switchs = {} + serveurs = {} + ferme = {} + + # tri des machines + for m in machines : + + # machine exclue + if m.nom() in self.exclude : + continue + + # les bornes + if m.canal() : + # C'est une borne + if m.info() : + # on regarde si c'est une borne de batiment + if ( m.info()[0][0:3] == "Au " ) and ( len(m.info()[0]) == 5 ) : + bornes[ "1-" + m.info()[0][4]+m.info()[0][3] + "-" + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ] + else : + bornes[ "2-" + m.info()[0] + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ] + else : + # on met les bornes non définies à la fin (ordre alphabétique) + bornes[ "3-" + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , 'Inutilise' ] + + # les switchs + elif m.info() and 'switch' in m.info()[0].lower() : + + # est ce que c'est un batiment + if 'bat' == m.nom()[0:3] : + index = '1-' + m.nom().split(".")[0] + else : + index = '0-' + m.nom().split(".")[0] + + # on ajoute au dictionnaire + switchs[ index ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ] + + # la ferme + elif '.ferme.crans.org' in m.nom() : + nom = ".".join(m.nom().split(".")[0:2]) + if m.info() : + ferme[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ] + else : + ferme[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , 'Infos non disponibles' ] + + # les serveurs + else : + if ".wifi.crans.org" in m.nom() : + nom = m.nom().split(".")[0] + ".wifi" + else : + nom = m.nom().split(".")[0] + if m.info() : + serveurs[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ] + else : + serveurs[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , 'Infos non disponibles' ] + + # route vers l'extérieur + ######################## + + # on récupère la route vers l'extérieur + traceroute = commands.getoutput("/usr/bin/traceroute www.free.fr 2> /dev/null | sed 's/\*//g' | sed 's/ */ /g' | sed 's/^ //g' | sed 's/[(,)]//g' | cut -d ' ' -f 2,3").split("\n") + + # initialisation des variables + in_renater = 0 + route_to_ext = '' + depends_to_ext = '' + + for routeur in traceroute : + + # on commence à rentrer dans la chaine des routeurs renater + if 'renater.fr' in routeur : + in_renater = 1 + + # on est plus dans les routeurs renater donc on arrête + if in_renater and not 'renater.fr' in routeur : + continue + + # ajout du routeur + + # ip + tmp_ip = routeur.split(' ')[1] + + # nom & desciption + if routeur.split(' ')[1] in self.infos_routeurs.keys() : + tmp_name = self.infos_routeurs[tmp_ip][0] + tmp_desc = self.infos_routeurs[tmp_ip][1] + else : + tmp_name = routeur.split(' ')[0].split('.')[0] + tmp_desc = 'Pas de description' + + # dépendances + if not depends_to_ext : + tmp_depends = 'none' + depends_to_ext = tmp_name + else : + tmp_depends = depends_to_ext + depends_to_ext += ',' + tmp_name + + # on l'ajoute à la route + if route_to_ext : + route_to_ext += '\n' + route_to_ext += '%s %s %s %s %s' % (tmp_name, tmp_ip, tmp_depends,self.mail_contact(tmp_name),tmp_desc) + + # services extérieurs + ##################### + + services_exterieurs = {} + for key in self.services_exterieurs.keys() : + s = self.services_exterieurs[key] + if s[2] : + services_exterieurs[ key ] = [ s[0] + ':' + str(s[2]), s[1] , depends_to_ext, s[4] , s[3] ] + else : + services_exterieurs[ key ] = [ s[0] , s[1] , depends_to_ext, s[4] , s[3] ] + + # génération du fichier + ####################### + + file = self._open_conf(self.CONFFILE, "#") + + # génère le dictionnaire pour les modifications + dico = {} + dico['switchs'] = self.make_config(switchs) + dico['bornes'] = self.make_config(bornes) + dico['serveurs'] = self.make_config(serveurs) + dico['ferme'] = self.make_config(ferme) + dico['route'] = route_to_ext.encode('iso-8859-15') + dico['exterieur'] = self.make_config(services_exterieurs) + + # on écrit dans le fichier de configuration + file.write( self.matrice % dico ) + + # on ferme le fichier + file.close() diff --git a/gestion/gest_crans.py b/gestion/gest_crans.py index e3bf944b..8deb72d0 100755 --- a/gestion/gest_crans.py +++ b/gestion/gest_crans.py @@ -1212,7 +1212,7 @@ def new_adher(adher) : if not no : mail = adher.mail() if mail.find('@')==-1 : mail += '@crans.org' - adher.services_to_restart('ML-ENS',[mail]) + adher.services_to_restart('ML_ens',[mail]) def modif_adher(adher) : """ diff --git a/gestion/ldap_crans.py b/gestion/ldap_crans.py index 45b04d03..f9189f15 100755 --- a/gestion/ldap_crans.py +++ b/gestion/ldap_crans.py @@ -21,6 +21,10 @@ elif hostname == "sila" : anon_bind = 1 # Anonyme pour lecture seule uri = 'ldapi://%2fvar%2frun%2fldapi/' rw_uri = 'ldaps://zamok.crans.org:636/' +elif hostname in [ 'bleu' , 'rouge' ] : + anon_bind = 0 # Anonyme pour lecture seule + uri = 'ldap://vert.adm.crans.org/' + rw_uri = uri else : anon_bind = 0 # Doit s'authentifier pour toute action uri = 'ldaps://sila.crans.org:636/' @@ -46,10 +50,6 @@ except : random.seed() # On initialise le générateur aléatoire -################################################################################## -### Différent services redémarrables -#dns, dhcp, firewall, bornes_wifi(nom_borne), conf_wifi, bl_carte_etudiant, switch(chbre), dhcp-nectaris - ################################################################################## ### Items de la blackliste blacklist_items = { u'bloq' : u'Bloquage total de tout services' , @@ -1130,15 +1130,14 @@ class base_proprietaire(base_classes_crans) : or 'paiement-%s' % ann_scol in self.modifs \ or ( config.bl_carte_et_definitif and test_carte ) : for m in self.machines() : - self.services_to_restart('firewall',[m.ip()] ) - self.services_to_restart('firewall-komaz',[m.ip()] ) + self.services_to_restart('macip',[m.ip()] ) self.services_to_restart('dns') if m.ipsec() : self.services_to_restart('conf_wifi') - self.services_to_restart('dhcp-nectaris') + self.services_to_restart('nectaris-dhcp') else : self.services_to_restart('switch',[self.chbre()]) - self.services_to_restart('dhcp') + self.services_to_restart('zamok-dhcp') # Vérification si changement de bât, ce qui obligerai un changement d'IP if 'chbre' in self.modifs and self.chbre()!='????' : @@ -1180,8 +1179,9 @@ class base_proprietaire(base_classes_crans) : # Modif des droits ? if 'droits' in self.modifs : - self.services_to_restart('droits',[self._data['uid']]) - + self.services_to_restart('droits') + self.services_to_restart('mail_modif',['uidNumber=%s' % self._data['uid']]) + # Remise à zero self.modifs=[] @@ -2213,15 +2213,15 @@ class machine(base_classes_crans) : # Reconfiguration firewalls et dhcps if reconf_ip : - self.services_to_restart('firewall' , reconf_ip) - self.services_to_restart('firewall-komaz' , reconf_ip) + self.services_to_restart('macip',reconf_ip ) if self.__typ == 'wifi' : - self.services_to_restart('dhcp-nectaris') + self.services_to_restart('nectaris-dhcp') else: - self.services_to_restart('dhcp') + self.services_to_restart('zamok-dhcp') if 'ports' in self.modifs : - self.services_to_restart('firewall-komaz-ports', [ self.ip() ] ) - + self.services_to_restart('komaz-ports', [ self.ip() ] ) + self.services_to_restart('mail_modif',['ip=%s' % self.ip()]) + # Reconfiguration DNS ? if 'host' in self.modifs or 'ipHostNumber' in self.modifs or 'hostAlias' in self.modifs : self.services_to_restart('dns') @@ -2243,7 +2243,7 @@ class machine(base_classes_crans) : # Regénération de l'autostatus et mail de changmement ? if self.proprietaire().__class__ == crans : self.services_to_restart('autostatus') - self.services_to_restart('mail_modification_machine',[self.ip()]) + self.services_to_restart('mail_modif',['ip=%s' % self.ip()]) # Remise à zéro self.modifs=[] @@ -2266,13 +2266,12 @@ class machine(base_classes_crans) : # Services à redémarrer if self.__typ == 'wifi' : self.services_to_restart('conf_wifi') - self.services_to_restart('dhcp-nectaris') + self.services_to_restart('nectaris-dhcp') else: - self.services_to_restart('dhcp') + self.services_to_restart('zamok-dhcp') self.services_to_restart('dns') - self.services_to_restart('firewall',[ self.ip() ]) - self.services_to_restart('firewall-komaz',[ self.ip() ]) + self.services_to_restart('macip',[self.ip()] ) def portTCPin(self,ports=None) : """ Ports TCP ouverts depuis l'extérieur pour la machine """ diff --git a/gestion/mail.py b/gestion/mail.py deleted file mode 100755 index 81a3bd20..00000000 --- a/gestion/mail.py +++ /dev/null @@ -1,53 +0,0 @@ -#! /usr/bin/env python -# -*- coding: iso-8859-15 -*- - -# Licence : GPLv2 - -import sys, smtplib -sys.path.append('/usr/scripts/gestion') - -from ldap_crans import smtpserv -from whos import machine_details, club_details, adher_details -from ldap_crans import adherent, club, machine - -def mail_details (Objets, Subject = "Modifications dans la base LDAP", To = ['roots@crans.org'], From = 'roots@crans.org', no_ascii = True ) : - """ - Envoie un mail à toutes les personnes de la liste 'To', avec les - informations détaillées des objets contenus dans 'Objets' - (instances des classes adherent, machine ou club) - - Si no_ascii est à True, on vire la couleur - """ - - if not len(Objets) : - return True - - base_txt_mail = """From: %(From)s -To: %(To)s -Subject: %(Subject)s - -%(Text)s""" - - details = [] - - for i in Objets : - if i.__class__ == machine : - details.append(machine_details(i)) - elif i.__class__ == adherent : - details.append(adher_details(i)) - elif i.__class__ == club : - details.append(club_details(i)) - else : - ok = False - - texte = '\n\n- - - - = = = = # # # # # # = = = = - - - -\n\n'.join(details) - - if no_ascii : - import sre - texte = sre.sub('\x1b\[1;([0-9]|[0-9][0-9])m','',texte) - - mail_complet = base_txt_mail % { 'From' : From, 'To' : ','.join(To), 'Subject' : Subject, 'Text' : texte.encode('iso8859-15') } - - conn=smtplib.SMTP(smtpserv) - conn.sendmail(From, To , mail_complet) - conn.quit() diff --git a/gestion/whos.py b/gestion/whos.py index 2820f084..d7f2a146 100755 --- a/gestion/whos.py +++ b/gestion/whos.py @@ -330,8 +330,8 @@ def adher_details(adher) : else : # Chambre + prise (d'après annuaire) f += coul(u'Chambre : ','gras') + u"%s " % chbre - f += '(%s)' % prise_etat(adher.chbre()) - f += '\n' + f += u'(%s)' % prise_etat(adher.chbre()) + f += u'\n' # Etudes if adher.etudes(1).isdigit() : @@ -527,8 +527,8 @@ def club_details(club) : # Chambre + prise f += coul(u'Local : ','gras') + "%s " % club.local() - f += '(%s)' % prise_etat(club.chbre()) - f += '\n' + f += u'(%s)' % prise_etat(club.chbre()) + f += u'\n' # Paiement if club.paiement() : @@ -667,30 +667,30 @@ def borne_clients(borne) : def prise_etat(chbre) : """ Retoune l'état de la prise associée à la chbre """ - f = '' - try : + f = u'' + try: # On met aussi l'état from hptools import sw_chbre prise = sw_chbre(chbre) - f += 'prise %s' % prise.prise_brute + f += u'prise %s' % prise.prise_brute rows, cols = get_screen_size() if prise.is_up() : - f += ', ' + coul('machine branchée','vert') + f += u', ' + coul(u'machine branchée','vert') reste_cols = cols - 45 if prise.eth_mode().find('10Mbits')!=-1 : - f+= ', ' + coul('prise en 10Mbps','jaune') + f+= u', ' + coul(u'prise en 10Mbps','jaune') reste_cols -= 17 f+=', ' macs = prise.show_prise_mac() if len(macs) == 0: if reste_cols < 20 : # Faut aller à la ligne - f += '\n ' - f += coul('aucune MAC détectée', 'jaune') + f += u'\n ' + f += coul(u'aucune MAC détectée', 'jaune') else: if len(macs) == 1 and reste_cols > 25 : # Une seule mac et on a assez de place - f += "MAC: %s" % macs[0] + f += u"MAC: %s" % macs[0] else : # On va à la ligne # Combien d'adresses MAC peut-on mettre par ligne ? @@ -700,18 +700,18 @@ def prise_etat(chbre) : count = 0 while len(macs) > 0: if count % parligne == 0: - f += '\n MACs: ' + f += u'\n MACs: ' else: - f += ', ' - f += "%s" % macs.pop() + f += u', ' + f += u"%s" % macs.pop() count += 1 elif not prise.is_enable() : - f+= ', ' + coul('prise désactivée','rouge') + f+= u', ' + coul(u'prise désactivée','rouge') else : - f+= ', activée, lien non détecté' + f+= u', activée, lien non détecté' except : # Switch non manageable - f = 'informations prise non disponibles' + f = u'informations prise non disponibles' return f